import datetime
import json
import logging
import math
import random
import re
import time
from decimal import Decimal
from json import JSONEncoder

from sqlalchemy import Date, and_, cast, func, or_

from base.connection import get_db_session, redis_util, mongodb_util
from common.definition import (
    AgencyType,
    BenefitType,
    CashMethod,
    OrderStatus,
    OrderType,
    PayStatus,
    PayType,
    ret_msg,
)
from conf import config, promotion
from conf.config import DOMAIN
from daemon import tasks
from helper.beanstalkd import add_mq_cash_task, add_mq_task
from helper.coupon_helper import CouponHandler
from helper.goods import is_goods_full_pkg
from helper.mp_helper import send_text_message
from helper.order import get_order
from helper.payment.balance import BalanceHandler
from helper.template_messages import balance_notice, new_customer_gift_order_reward_notice

logger = logging.getLogger('payment')


class OrderInfoInvalid(Exception):
    pass


def generator_trade_no():
    """
    生成订单号
    :return: 订单号
    """
    t = int(1000 * time.time())
    r = random.randint(1000, 9999)
    return ''.join(map(lambda i: str(i), (t, r)))


def calculate_order_fee(goods_info_arr, benefit_type=BenefitType.PARENT, store_id=0):
    """
    计算订单的提成金额

    >>> calculate_order_fee(
    ... json.dumps([
    ...      {
    ...        'id': '496641881103104',
    ...        'count': 1,
    ...        'goods_img': 'http://a.cn/a.jpg',
    ...        'goods_name': 'wine',
    ...        'goods_price': 49.0,
    ...        'goods_member_price': 49.0,
    ...        'balance_rate': 0.1,
    ...        'rate': 0.1,
    ...        'master_rate': 0.1,
    ...        'invite_rate': 0.05,
    ...        'invite_invite_rate': 0.03,
    ...        'career_rate': 0.05,
    ...        'invite_career_rate': 0.05
    ...      }
    ...    ]),BenefitType.PARENT)
    (Decimal('4.90'), 0.1)

    >>> calculate_order_fee(
    ... json.dumps([
    ...  {
    ...    'id': '496641881103104',
    ...    'count': 1,
    ...    'goods_img': 'http://a.cn/a.jpg',
    ...    'goods_name': 'wine',
    ...    'goods_price': 49.0,
    ...    'goods_member_price': 49.0,
    ...    'balance_rate': 0.1,
    ...        'rate': 0.1,
    ...        'master_rate': 0.1,
    ...        'invite_rate': 0.05,
    ...        'invite_invite_rate': 0.03,
    ...        'career_rate': 0.05,
    ...        'invite_career_rate': 0.05
    ...      }
    ...    ]),BenefitType.INVITE_CAREER)
    (Decimal('2.45'), 0.05)

    :param goods_info_arr:
    :param benefit_type:
    :return:
    """
    if isinstance(goods_info_arr, str):
        goods_info_arr = json.loads(goods_info_arr)

    total_price = Decimal('0.00')
    total_benefit = Decimal('0.00')
    rate = 0
    for g in goods_info_arr:
        # 用会员价来计算收益
        price = float(g['goods_price'])  # 此处为兼容旧的商品信息
        if g.get('goods_member_price'):
            price = float(g['goods_member_price'])

        if benefit_type == BenefitType.PARENT:
            rate = float(g['master_rate']) if g['master_rate'] else float(g['rate'])
        elif benefit_type == BenefitType.CAREER:
            # 事业部分润基数修改为门店进货价-20201108
            if g.get('goods_pin_price'):
                price = float(g['goods_pin_price'])
            rate = float(g['career_rate'])
        elif benefit_type == BenefitType.INVITE_PARENT:
            # 邀请合伙人分润基数修改为门店进货价-20211213
            if g.get('goods_pin_price'):
                price = float(g['goods_pin_price'])
            rate = float(g['invite_rate'])
        elif benefit_type == BenefitType.INVITE_INVITE_PARENT:
            rate = 0  # 兼容旧商品信息处理
            if g.get('invite_invite_rate'):
                rate = float(g['invite_invite_rate'])
        elif benefit_type == BenefitType.INVITE_CAREER:
            # 邀请事业部分润基数修改为门店进货价-20201108
            if g.get('goods_pin_price'):
                price = float(g['goods_pin_price'])
            rate = 0  # 兼容旧商品信息处理
            if g.get('invite_career_rate'):
                rate = float(g['invite_career_rate'])
        # 新增线上分润类型 - 20190416
        elif benefit_type == BenefitType.NEW_PARTNER:
            rate = (
                float(g['master_rate']) if g['master_rate'] else float(g['rate'])
            )  # 统一
        elif benefit_type == BenefitType.INVITE_NEW_PARTNER:
            rate = float(g['invite_rate']) if g['invite_rate'] else 0.05  # 5%
        elif benefit_type == BenefitType.INVESTOR:
            rate = (
                float(g['master_rate']) if g['master_rate'] else float(g['rate'])
            )  # 10% -> ~15% lijim 20191018
        elif benefit_type == BenefitType.INVITE_INVESTOR:
            rate = 0  # 0%
        elif benefit_type == BenefitType.STORE:
            rate = 0  # 20% -> 0% 20190815
        elif benefit_type == BenefitType.INVITE_STORE:
            rate = float(g['invite_rate'])  # 3% 20191018
        elif benefit_type == BenefitType.INVITE_INVITE_STORE:
            rate = float(g['invite_rate'])  # 3% 20191018
        elif benefit_type == BenefitType.CLERK:
            rate = float(g['invite_rate'])  # 3% 20191018
        elif benefit_type == BenefitType.INVITE_CLERK:
            rate = 0  # 0% TBD
        # 新增线下分润类型  - 20190416
        elif g['id'] != '568105146613081':
            if benefit_type == BenefitType.STORE_OFFLINE:
                if store_id < 2640:
                    rate = 0.30  # 老门店分润 30%
                else:
                    rate = 0.20  # 20% - 新门店分润
            elif benefit_type == BenefitType.INVITE_STORE_OFFLINE:
                rate = 0.05  # 5%
            elif benefit_type == BenefitType.INVITE_INVITE_STORE_OFFLINE:
                rate = 0.05  # 3%->5% 20191022
            elif benefit_type == BenefitType.INVESTOR_OFFLINE:
                rate = 0.15  # 10%->15% 20191018
            elif benefit_type == BenefitType.INVITE_INVESTOR_OFFLINE:
                rate = 0  # 3%->0% 20191018
            elif benefit_type == BenefitType.CLERK_OFFLINE:
                rate = 0.08  # 8%
            elif benefit_type == BenefitType.INVITE_CLERK_OFFLINE:
                rate = 0  # 0% TBD
            elif benefit_type == BenefitType.STORE_FREECARD:
                rate = (
                    float(g['master_rate']) if g['master_rate'] else float(g['rate'])
                )  # 门店买单餐费 默认80%
            else:
                raise Exception('未知的收益类型')
        else:  # g['id'] == '568105146613081'  # 39元杯中酒特别分润比例 20191015
            if benefit_type == BenefitType.STORE_OFFLINE:
                rate = 0.30  # 50%->30% 20191022
            elif benefit_type == BenefitType.INVITE_STORE_OFFLINE:
                rate = 0
            elif benefit_type == BenefitType.INVITE_INVITE_STORE_OFFLINE:
                rate = 0
            elif benefit_type == BenefitType.INVESTOR_OFFLINE:
                rate = 0
            elif benefit_type == BenefitType.INVITE_INVESTOR_OFFLINE:
                rate = 0
            elif benefit_type == BenefitType.CLERK_OFFLINE:
                rate = 0
            elif benefit_type == BenefitType.INVITE_CLERK_OFFLINE:
                rate = 0
            else:
                raise Exception('未知的收益类型')

        total_price += Decimal(price * float(g['count']))
        total_benefit += Decimal(price * rate * float(g['count']))
    total_benefit = total_benefit.quantize(Decimal('1.00'))
    rate = float(total_benefit / total_price)
    return total_benefit, rate


class BenefitBackend(object):
    def __init__(self):
        pass

    @staticmethod
    def inspect(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        检查费用是否合法

        >>> BenefitBackend.inspect(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 6,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 49.9,
        ...    'goods_member_price': 49.9,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ...  }
        ... ], Decimal('299.40'), Decimal('0.00'), Decimal('0.00'),  Decimal('0.00'))
        True

        :param goods_info: 订单的商品快照 list
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return: 费用是否合法 boolean
        """
        con1 = isinstance(cash_fee, Decimal)
        con2 = isinstance(balance_fee, Decimal)
        con3 = isinstance(coupon_fee, Decimal)
        con4 = isinstance(delivery_fee, Decimal)
        if not (isinstance(goods_info, list) and con1 and con2 and con3 and con4):
            logger.error(
                f'订单信息不合法 goods={goods_info} cash={cash_fee} balance={balance_fee} coupon={coupon_fee}'
            )
            return False

        total_fee = Decimal('0.00')
        for g in goods_info:
            count = Decimal(str(g['count']))
            if order_type == OrderType.PINGUI:
                goods_price = Decimal(str(g['goods_pin_price']))
            elif order_type == OrderType.DISTRIBUTOR:
                goods_price = Decimal(str(g['goods_member_price']))
            else:
                goods_price = Decimal(str(g['goods_price']))
            total_fee += count * goods_price
        # total_fee += delivery_fee  # 增加运费 -> 20220401: 计算前cash_fee已经扣减运费, 所以不用考虑运费了
        if total_fee.quantize(Decimal('0.00')) == (
                cash_fee + balance_fee + coupon_fee
        ).quantize(Decimal('0.00')):
            return True
        logger.error(
            f'订单信息不合法: 订单总额对不上！ goods={goods_info} total={total_fee} delivery={delivery_fee} cash={cash_fee} balance={balance_fee} coupon={coupon_fee} order_type={order_type}'
        )
        return False

    @staticmethod
    def calculate_differ(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算会员价与非会员价差价部分

        >>> BenefitBackend.calculate_differ(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 49.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ... }
        ... ], Decimal(120), Decimal(0), Decimal(0),  Decimal('0.00'))
        Decimal('22.00')

        :param goods_info: 订单的商品快照
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return:
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')

        # 差价
        # 微信和余额混合支付的要按比例扣除余额部分(非会员支付时没有余额的)
        differ_fee = Decimal('0.00')
        for g in goods_info:
            count = Decimal(g['count'])
            goods_price = Decimal(g['goods_price']).quantize(Decimal('0.00'))
            goods_member_price = Decimal(g['goods_member_price']).quantize(Decimal('0.00'))
            goods_id = g['id']
            if goods_member_price > goods_price:
                # 会员价不能大于非会员价
                logger.error(
                    f'calculate_differ: 差价为0，价格低于会员价 goods_id={goods_id}, goods_price={goods_price}, goods_member_price={goods_member_price}'
                )
                continue
            if goods_member_price:
                differ_fee += count * (goods_price - goods_member_price)
        logger.debug(f'differ_fee={differ_fee}')

        if config.IS_CALCULATE_BALANCE_BENEFIT:
            differ_fee *= Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            differ_fee *= Decimal(cash_fee / (cash_fee + balance_fee + coupon_fee))

        logger.debug(
            f'differ_fee_after_rate = {differ_fee}: IS_CALCULATE_BALANCE_BENEFIT={config.IS_CALCULATE_BALANCE_BENEFIT}'
        )
        return differ_fee.quantize(Decimal('1.00'))

    @staticmethod
    def calculate_store_differ(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算门店进货价和合伙人内部价的差价

        >>> BenefitBackend.calculate_store_differ(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 49.0,
        ...    'goods_pin_price': 39.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ... }
        ... ], Decimal(120), Decimal(0), Decimal(0), Decimal('0.00'))
        Decimal('20.00')

        :param goods_info: 订单的商品快照 json_array
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return:
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')

        # 门店进货价和内部价的差价
        # 微信和余额混合支付的要按比例扣除余额部分(非会员支付时没有余额的)
        differ_fee = Decimal('0.00')
        for g in goods_info:
            goods_id = g['id']
            count = Decimal(g['count'])
            goods_price = Decimal(g['goods_price'])
            goods_member_price = Decimal(g['goods_member_price']).quantize(Decimal('0.00'))
            goods_pin_price = Decimal(g['goods_pin_price']).quantize(Decimal('0.00'))
            if goods_member_price >= goods_pin_price >= 0:
                differ_fee += count * (goods_member_price - goods_pin_price)
            else:
                logger.error(
                    f'calculate_store_differ: goods_member_price >= goods_pin_price >= 0 不成立 goods_id={goods_id}'
                )
        logger.debug(f'calculate_store_differ: store_differ_fee={differ_fee}')

        if config.IS_CALCULATE_BALANCE_BENEFIT:
            differ_fee *= Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            differ_fee *= Decimal(cash_fee / (cash_fee + balance_fee + coupon_fee))
        logger.debug(
            f'differ_fee_after_rate = {differ_fee}: IS_CALCULATE_BALANCE_BENEFIT={config.IS_CALCULATE_BALANCE_BENEFIT}'
        )
        return differ_fee.quantize(Decimal('1.00'))

    @staticmethod
    def calculate_parent_benefit(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算直属合伙人收益金额

        >>> BenefitBackend.calculate_parent_benefit(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 49.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ...  }
        ... ], Decimal(120), Decimal(0), Decimal(0), Decimal(0))
        (Decimal('9.80'), 0.1)

        :param goods_info: 订单的商品快照
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return:
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')
        price_total, rate = calculate_order_fee(goods_info, BenefitType.PARENT)
        if config.IS_CALCULATE_BALANCE_BENEFIT:
            real_total_price = price_total * Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            real_total_price = price_total * Decimal(
                cash_fee / (cash_fee + balance_fee + coupon_fee)
            )

        return real_total_price.quantize(Decimal('1.00')), rate

    @staticmethod
    def calculate_invite_parent_benefit(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算直属合伙人邀请人收益金额

        >>> BenefitBackend.calculate_invite_parent_benefit(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 49.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ...  }
        ... ], Decimal(120), Decimal(0), Decimal(0), Decimal(0))
        (Decimal('4.90'), 0.05)

        :param goods_info: 订单的商品快照
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return:
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')
        price_total, rate = calculate_order_fee(goods_info, BenefitType.INVITE_PARENT)
        if config.IS_CALCULATE_BALANCE_BENEFIT:
            real_total_price = price_total * Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            real_total_price = price_total * Decimal(
                cash_fee / (cash_fee + balance_fee + coupon_fee)
            )
        return real_total_price.quantize(Decimal('1.00')), rate

    @staticmethod
    def calculate_career_benefit(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算事业合伙人收益金额

        >>> BenefitBackend.calculate_career_benefit(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 59.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ...  }
        ... ], Decimal(120), Decimal(0), Decimal(0), Decimal(0))
        (Decimal('5.90'), 0.05)

        :param goods_info: 订单的商品快照
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return:
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')
        price_total, rate = calculate_order_fee(goods_info, BenefitType.CAREER)
        if config.IS_CALCULATE_BALANCE_BENEFIT:
            real_total_price = price_total * Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            real_total_price = price_total * Decimal(
                cash_fee / (cash_fee + balance_fee + coupon_fee)
            )
        return real_total_price.quantize(Decimal('1.00')), rate

    @staticmethod
    def calculate_invite_career_benefit(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算事业合伙人邀请人收益金额

        >>> BenefitBackend.calculate_invite_career_benefit(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 59.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ...  }
        ... ], Decimal(120), Decimal(0), Decimal(0), Decimal(0))
        (Decimal('5.90'), 0.05)

        :param goods_info: 订单的商品快照
        :param cash_fee: 现金支付金额 decimal
        :param balance_fee: 余额支付金额 decimal
        :param coupon_fee: 优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return:
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')
        price_total, rate = calculate_order_fee(goods_info, BenefitType.INVITE_CAREER)

        if config.IS_CALCULATE_BALANCE_BENEFIT:
            real_total_price = price_total * Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            real_total_price = price_total * Decimal(
                cash_fee / (cash_fee + balance_fee + coupon_fee)
            )

        return real_total_price.quantize(Decimal('1.00')), rate

    @staticmethod
    def calculate_benefit(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            benefit_type,
            order_type=OrderType.NORMAL,
            store_id=0,
    ):
        """
        按收益类型计算合伙人收益金额

        >>> BenefitBackend.calculate_benefit(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 59.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05
        ...  }
        ... ],Decimal(120), Decimal(0), Decimal(0), Decimal(0), BenefitType.INVITE_PARENT)
        (Decimal('5.90'), 0.05)

        :param goods_info: 商品信息数组 array
        :param cash_fee: 现金 decimal
        :param balance_fee: 余额 decimal
        :param coupon_fee:  优惠券金额 decimal
        :param benefit_type: 收益类型 int
        :param store_id: 门店ID
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return: benefit: 实际收益 decimal
        :return: rate: 实际收益率 float
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')
        benefit, rate = calculate_order_fee(goods_info, benefit_type, store_id)

        if config.IS_CALCULATE_BALANCE_BENEFIT:
            real_benefit = benefit * Decimal(
                (cash_fee + balance_fee) / (cash_fee + balance_fee + coupon_fee)
            )
        else:
            real_benefit = benefit * Decimal(
                cash_fee / (cash_fee + balance_fee + coupon_fee)
            )
        return real_benefit.quantize(Decimal('1.00')), rate

    @staticmethod
    def calculate_supplier_benefit(
            goods_info,
            cash_fee,
            balance_fee,
            coupon_fee,
            delivery_fee,
            order_type=OrderType.NORMAL,
    ):
        """
        计算供应商金额

        >>> BenefitBackend.calculate_supplier_benefit(
        ... [
        ...  {
        ...    'id': '496641881103104',
        ...    'count': 2,
        ...    'goods_img': '',
        ...    'goods_name': '2015',
        ...    'goods_price': 60.0,
        ...    'goods_member_price': 59.0,
        ...    'balance_rate': 0.1,
        ...    'rate': 0.1,
        ...    'master_rate': 0.1,
        ...    'invite_rate': 0.05,
        ...    'invite_invite_rate': 0.03,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05,
        ...    'supplier': 0,
        ...    'goods_cost': 45.0
        ...  },
        ...  {
        ...    'id': '588571403508579',
        ...    'count': 6,
        ...    'goods_img': 'https://style-1251902022.file.myqcloud.com/static/img/activities/20200504134408.png',
        ...    'goods_name': '\u3010\u6fb3\u6d32\u30112016\u5e84\u56ed\u8001\u85e4\u8d64\u971e\u73e0\u897f\u62c9\u5e72\u7ea2\u8461\u8404\u9152',
        ...    'goods_price': 68.0,
        ...    'goods_member_price': 103.0,
        ...    'goods_pin_price': 68.0,
        ...    'balance_rate': 0,
        ...    'rate': 0.0,
        ...    'master_rate': 0.0,
        ...    'invite_rate': 0.1,
        ...    'invite_invite_rate': 0.0,
        ...    'career_rate': 0.05,
        ...    'invite_career_rate': 0.05,
        ...    'supplier': 1,
        ...    'goods_cost': 45.7
        ...  }
        ... ],Decimal(528), Decimal(0), Decimal(0), Decimal(0), Decimal(0))
        [{'supplier': 0, 'cost': Decimal('90.00')}, {'supplier': 1, 'cost': Decimal('274.20')}]

        :param goods_info: 商品信息数组 array
        :param cash_fee: 现金 decimal
        :param balance_fee: 余额 decimal
        :param coupon_fee:  优惠券金额 decimal
        :param delivery_fee: 运费 decimal
        :param order_type: 订单类型 int
        :return: cost_matrix: supplier cost matrix
        """
        if not BenefitBackend.inspect(
                goods_info, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        ):
            raise OrderInfoInvalid('订单信息不合法')

        if isinstance(goods_info, str):
            goods_info = json.loads(goods_info)

        # get suppliers
        suppliers = []
        for g in goods_info:
            supplier = g['supplier']
            if supplier not in suppliers:
                suppliers.append(supplier)

        # get supplier cost matrix
        cost_matrix = []
        for s in suppliers:
            total_cost = Decimal('0')
            for g in goods_info:
                supplier = g['supplier']

                if s == supplier:
                    cost = float(g['goods_cost'])
                    total_cost += Decimal(cost * float(g['count']))
            total_benefit = total_cost.quantize(Decimal('1.00'))
            cost_matrix.append({'supplier': s, 'cost': total_benefit})
        return cost_matrix


class BenefitHelper(object):
    def __init__(self):
        pass

    @staticmethod
    def create_benefit_record(
            benefit_type, order_id, agency_uid, fee, order_fee, rate, remarks=None
    ):
        """
        创建收益订单

        :param order_id: 订单号
        :param agency_uid: 代理商uid
        :param benefit_type: 收益类型
        :param fee: 收益金额
        :param order_fee: 订单金额
        :param rate: 收益率
        :param remarks: 备注
        :return: None
        """

        class Benefit(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'sdet_benefit', 'model': Benefit},
            ]
        )

        # 幂等性处理：同一订单，同一合伙人，同一的分润类型要唯一
        old_benefit = (
            session.query(Benefit)
            .filter_by(order_id=order_id, agency_uid=agency_uid, type=benefit_type)
            .first()
        )
        if old_benefit:
            logger.info(
                f'创建收益订单: NG: 收益订单已经存在！order_id={order_id}, agency_uid={agency_uid}, type={benefit_type}'
            )
            return
        elif fee:  # > Decimal('0.00'):  # 允许负收益-20220416
            now = datetime.datetime.now()
            benefit = Benefit()
            benefit.order_id = order_id
            benefit.factory_uid = config.FACTORY_UID
            benefit.agency_uid = agency_uid
            benefit.type = benefit_type
            benefit.fee = fee
            benefit.order_fee = order_fee
            benefit.rate = rate
            benefit.status = 0
            benefit.is_valid = 1
            benefit.is_finish = 0
            benefit.remarks = remarks
            benefit.update_time = now
            benefit.create_time = now
            session.add(benefit)
            session.commit()
            logger.info(
                f'创建收益订单: OK: order_id={order_id}, agency_uid={agency_uid}, type={benefit_type}, benefit={fee}, rate={rate}'
            )
        else:
            logger.error(
                f'创建收益订单: NG: 收益金额不大于0! order_id={order_id}, agency_uid={agency_uid}, type={benefit_type}, benefit={fee}'
            )
        session.close()

    @staticmethod
    def create_completed_benefit_record(
            benefit_type, order_id, agency_uid, fee, order_fee, rate, remarks=None
    ):
        """
        创建实时结算收益订单

        :param order_id: 订单号
        :param agency_uid: 代理商uid
        :param benefit_type: 收益类型
        :param fee: 收益金额
        :param order_fee: 订单金额
        :param rate: 收益率
        :param remarks: 备注
        :return: None
        """

        class Benefit(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'sdet_benefit', 'model': Benefit},
            ]
        )

        # 幂等性处理：同一订单，同一合伙人，同一的分润类型要唯一
        old_benefit = (
            session.query(Benefit)
            .filter_by(order_id=order_id, agency_uid=agency_uid, type=benefit_type)
            .first()
        )
        if old_benefit:
            logger.info(
                f'创建实时结算收益订单: NG: 收益订单已经存在！order_id={order_id}, agency_uid={agency_uid}, type={benefit_type}'
            )
        elif fee > Decimal('0.00'):
            now = datetime.datetime.now()
            benefit = Benefit()
            benefit.order_id = order_id
            benefit.factory_uid = config.FACTORY_UID
            benefit.agency_uid = agency_uid
            benefit.type = benefit_type
            benefit.fee = fee
            benefit.order_fee = order_fee
            benefit.rate = rate
            benefit.status = 1
            benefit.is_valid = 1
            benefit.is_finish = 1
            benefit.remarks = remarks
            benefit.update_time = now
            benefit.create_time = now
            session.add(benefit)
            session.commit()
            logger.info(
                f'创建实时结算收益订单: OK: order_id={order_id}, agency_uid={agency_uid}, type={benefit_type}, benefit={fee}, rate={rate}'
            )
        else:
            logger.error(
                f'创建实时结算收益订单: 收益金额不大于0! order_id={order_id}, agency_uid={agency_uid}, type={benefit_type}, benefit={fee}, rate={rate}'
            )
        session.close()

    @staticmethod
    def create_differ_benefit(order_id, agency_uid, fee, order_fee, remarks=None):
        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        # 检查直属上级合伙人是否为 专业合伙人(事业合伙人也是可以获取差价的)
        agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
        if agency and agency.ebf_agency_type not in [
            AgencyType.PROFESSIONAL,
            AgencyType.CAREER,
        ]:
            logger.error(f'只有专业合伙人和事业合伙人才能提成差价：agency_uid={agency_uid}')
            session.close()
            return
        logger.info(
            f'创建差价收益订单: order_id={order_id}, agency_uid={agency_uid}, benefit={fee}'
        )
        BenefitHelper.create_benefit_record(
            BenefitType.DIFFER, order_id, agency_uid, fee, order_fee, 0, remarks
        )

    @staticmethod
    def create_normal_agency_benefit(
            order_id, agency_uid, fee, order_fee, rate, remarks=None
    ):
        logger.info(
            f'创建普通收益订单: order_id={order_id}, agency_uid={agency_uid}, benefit={fee}'
        )
        BenefitHelper.create_benefit_record(
            BenefitType.PARENT, order_id, agency_uid, fee, order_fee, rate, remarks
        )

    @staticmethod
    def create_invite_normal_agency_benefit(
            order_id, agency_uid, fee, order_fee, rate, remarks=None
    ):
        logger.info(
            f'创建推荐人收益订单: order_id={order_id}, agency_uid={agency_uid}, benefit={fee}'
        )
        BenefitHelper.create_benefit_record(
            BenefitType.INVITE_PARENT,
            order_id,
            agency_uid,
            fee,
            order_fee,
            rate,
            remarks,
        )

    @staticmethod
    def create_career_agency_benefit(
            order_id, agency_uid, fee, order_fee, rate, remarks=None
    ):
        logger.info(
            f'创建事业合伙人收益订单: order_id={order_id}, agency_uid={agency_uid}, benefit={fee}'
        )
        BenefitHelper.create_benefit_record(
            BenefitType.CAREER, order_id, agency_uid, fee, order_fee, rate, remarks
        )

    @staticmethod
    def create_invite_career_agency_benefit(
            order_id, agency_uid, fee, order_fee, rate, remarks=None
    ):
        logger.info(
            f'创建事业合伙人推荐人收益订单: order_id={order_id}, agency_uid={agency_uid}, benefit={fee}'
        )
        BenefitHelper.create_benefit_record(
            BenefitType.INVITE_CAREER,
            order_id,
            agency_uid,
            fee,
            order_fee,
            rate,
            remarks,
        )

    @staticmethod
    def create_benefit(
            benefit_type, order_id, agency_uid, benefit, order_fee, rate, remarks=None
    ):
        logger.info(
            f'创建收益订单: order_id={order_id}, agency_uid={agency_uid}, benefit_type={benefit_type}, benefit={benefit}'
        )
        BenefitHelper.create_benefit_record(
            benefit_type, order_id, agency_uid, benefit, order_fee, rate, remarks
        )

    @staticmethod
    def create_complete_order(order_id):
        """
        将预收益订单更新为完成，同时创建提成订单（兼容旧提成）

        :param order_id:
        :return:
        """

        class GoodsOrder(object):
            pass

        class Pay(object):
            pass

        class Agency(object):
            pass

        class Benefit(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'sdet_order', 'model': GoodsOrder},
                {'db_table': 'ebt_pay', 'model': Pay},
                {'db_table': 'ebt_agency', 'model': Agency},
                {'db_table': 'sdet_benefit', 'model': Benefit},
            ]
        )
        pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()

        now = datetime.datetime.utcnow()
        user_id = pay.sdef_order_device_id

        benefits = session.query(Benefit).filter_by(order_id=order_id).all()
        for b in benefits:
            if b.is_finish == 1 or b.is_valid == 0 or b.status == 2:
                logger.error(
                    f'结算收益: 已完成、无效、已退款的收益不能结算: order_id={order_id}, benefit_id={b.id}, finish={b.is_finish}, valid={b.is_valid}, status={b.status}'
                )
                continue
            b.is_finish = 1
            b.status = 1
            b.update_time = datetime.datetime.now()

            agency_uid = b.agency_uid
            out_trade_no = generator_trade_no()

            # 兼容旧系统处理
            if pay.sdef_order_pay_type != PayType.BALANCE:
                pay1 = Pay()
                pay1.ebf_device_id = None
                pay1.ebf_user_id = user_id
                pay1.ebf_pay_trade_no = out_trade_no
                pay1.ebf_pay_fee = b.fee
                pay1.ebf_pay_is_success = 1
                pay1.ebf_pay_create_date = now
                pay1.ebf_pay_type = 2
                pay1.ebf_pay_trade_type = 1
                pay1.ebf_pay_content = '微信支付'
                pay1.ebf_pay_remarks = f'order_id={order_id}'
                pay1.ebf_pay_status = 1
                pay1.ebf_pay_pay_date = now

                agency = (
                    session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
                )
                if agency:
                    pay1.ebf_pay_agency_id = agency.ebf_agency_id
                else:
                    pay1.ebf_pay_agency_id = None

                pay1.ebf_pay_factory_id = config.FACTORY_ID
                pay1.ebf_pay_account = ''
                pay1.ebf_pay_remote_ip = ''
                session.add(pay1)

            session.commit()
        logger.info(f'ebt_pay提成计算完成:order_id={order_id}')
        session.close()

    @staticmethod
    def update_benefit_refund(order_id):
        class Benefit(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'sdet_benefit', 'model': Benefit},
            ]
        )

        now = datetime.datetime.now()
        update_fields = {
            Benefit.status: 2,
            Benefit.is_finish: 1,
            Benefit.update_time: now,
            Benefit.is_valid: 0,
        }
        result = (
            session.query(Benefit)
            .filter_by(order_id=order_id, is_finish=0)
            .update(update_fields)
        )
        session.commit()
        logger.info(f'更新收益订单为退款：result={result}')


class AgencyHelper(object):
    @staticmethod
    def get_user(open_id):
        class User(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user', 'model': User},
            ]
        )
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        session.close()
        return user

    @staticmethod
    def get_recommender_id(open_id):
        class User(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user', 'model': User},
            ]
        )
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        session.close()
        return user.ebf_user_recommend_user

    @staticmethod
    def get_agency_uid(open_id):
        """
        根据合伙人open_id获取uid

        :param open_id: 合伙人的open_id
        :return: agency_uid
        """

        class UserAgency(object):
            pass

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user_agency', 'model': UserAgency},
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        user_agency = (
            session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        )
        if not user_agency:
            session.close()
            return None

        agency = (
            session.query(Agency)
            .filter_by(ebf_agency_id=user_agency.ebf_agency_id)
            .first()
        )
        if not agency:
            session.close()
            return None

        agency_uid = agency.ebf_agency_uid
        session.close()
        return agency_uid

    @staticmethod
    def get_agency_openid(agency_id):
        """
        查找合伙人绑定的open_id

        AgencyHelper.get_agency_openid(119)
        'o7qyl0i6R30kbFS7KPFVGwYb05pY'

        :param agency_id: int
        :return: agency open_id: string
        """

        class UserAgency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user_agency', 'model': UserAgency},
            ]
        )

        user_agency = (
            session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
        )
        if not user_agency:
            logger.error(f'当前合伙人账户未绑定微信: agency_id={agency_id}')
            session.close()
            return None

        agency_openid = user_agency.ebf_ua_bind_user_id
        session.close()
        return agency_openid

    @staticmethod
    def get_career_agency(agency_uid):
        """
        通过合伙人ID/UID获取合伙人事业部记录

        UserHelper.get_career_agency(119)

        UserHelper.get_career_agency('119')

        UserHelper.get_career_agency('f7fd0668-5a3a-11e7-9315-00a0d1ed4d50')

        """

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        filters = dict()
        if type(agency_uid) is int or re.match(r'^\d+$', agency_uid):
            filters['ebf_agency_id'] = agency_uid
        else:
            filters['ebf_agency_uid'] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            logger.error(f'get_career_agency: agency_uid={agency_uid} 合伙人记录不存在')
            session.close()
            return None

        agency_type = agency.ebf_agency_type
        agency_sub_type = agency.ebf_agency_sub_type
        # 检查当前用户自己是否为事业合伙人, 包括: 行家3.2 新事业部3.3
        if agency_type == AgencyType.CAREER or (
                agency_type == AgencyType.STORE and agency_sub_type > 1
        ):
            logger.info(f'get_career_agency: agency_uid={agency_uid} 该合伙人自己就是事业合伙人')
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            logger.info(f'get_career_agency: agency_uid={agency_uid} 该合伙人没有上级')
            session.close()
            return None

        # 找到级别里直属合伙人最近的事业合伙人
        career_agency = None
        agency_id = agency.ebf_agency_parent_id
        count = 0
        while agency_id and agency_id > 0:
            last_agency = (
                session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            )
            if last_agency:
                agency_id = last_agency.ebf_agency_parent_id
                agency_type = last_agency.ebf_agency_type
                agency_sub_type = last_agency.ebf_agency_sub_type
                count += 1
                # 检查是否为事业合伙人, 包括: 行家3.2 新事业部3.3
                if agency_type == AgencyType.CAREER or (
                        agency_type == AgencyType.STORE and agency_sub_type > 1
                ):
                    career_agency = last_agency
                    break
                # 避免账号死循环的情况
                if count > 100:
                    logger.error(
                        f'get_career_agency: level > 100 agency_id={agency_id}'
                    )
                    break
        logger.info(
            f'get_career_agency: agency_uid={agency_uid} career_agency_id={career_agency.ebf_agency_id if career_agency else 0}'
        )
        session.close()
        return career_agency

    @staticmethod
    def get_super_agency(agency_uid):
        """
        通过合伙人ID/UID获取合伙人超级事业部记录

        UserHelper.get_career_agency(119)

        UserHelper.get_career_agency('f7fd0668-5a3a-11e7-9315-00a0d1ed4d50')

        """

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        filters = dict()
        if type(agency_uid) is int or re.match(r'^\d+$', agency_uid):
            filters['ebf_agency_id'] = agency_uid
        else:
            filters['ebf_agency_uid'] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            logger.error(f'get_super_agency: agency_uid={agency_uid} 合伙人记录不存在')
            session.close()
            return None

        # 检查当前用户自己是否为超级事业合伙人
        agency_id = agency.ebf_agency_id
        if agency_id in config.SUPER_AGENCY_ID:
            logger.info(f'get_super_agency: agency_id={agency_id} 该合伙人自己就是超级事业合伙人')
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            logger.info(f'get_super_agency: agency_uid={agency_uid} 该合伙人没有上级')
            session.close()
            return None

        # 查找最近的超级事业合伙人
        super_agency = None
        agency_id = agency.ebf_agency_parent_id
        count = 0
        while agency_id and agency_id > 0:
            last_agency = (
                session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            )
            if last_agency:
                # 检查是否为超级事业合伙人
                if agency_id in config.SUPER_AGENCY_ID:
                    super_agency = last_agency
                    break
                # 避免账号死循环的情况
                agency_id = last_agency.ebf_agency_parent_id
                count += 1
                if count > 100:
                    logger.error(
                        f'get_career_agency: level > 100 agency_id={agency_id}'
                    )
                    break
        logger.info(
            f'get_super_agency: agency_uid={agency_uid} super_agency_id={super_agency.ebf_agency_id if super_agency else 0}'
        )
        session.close()
        return super_agency

    @staticmethod
    def get_agency(agency_id):
        """
        通过合伙人ID/UID获取合伙人记录
        """
        logger.debug(f'获取合伙人记录，agency_id={agency_id}')

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        filters = dict()
        if isinstance(agency_id, int) or re.match('^/d+$', agency_id):
            filters['ebf_agency_id'] = agency_id
        else:
            filters['ebf_agency_uid'] = agency_id

        agency = session.query(Agency).filter_by(**filters).first()
        session.close()
        return agency

    @staticmethod
    def get_user_bind_agency(open_id):
        """
        通过合伙人绑定的Open_ID获取合伙人记录
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f'获取合伙人记录，open_id={open_id}')

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user', 'model': User},
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = (
            session.query(Agency)
            .filter_by(ebf_agency_uid=user.ebf_user_agency_uid)
            .first()
        )
        session.close()
        return agency

    @staticmethod
    def get_user_agency(open_id):
        """
        获取用户所属合伙人

        通过用户Open_ID获取用户所属合伙人记录

        通过合伙人的用户ID获取到的合伙人记录就是该合伙人的记录
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f'获取合伙人记录，open_id={open_id}')

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user', 'model': User},
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = (
            session.query(Agency)
            .filter_by(ebf_agency_uid=user.ebf_user_agency_uid)
            .first()
        )
        session.close()
        return agency

    @staticmethod
    def get_user_agency_uid(open_id):
        """
        通过用户Open_ID获取用户所属合伙人的记录
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f'获取合伙人记录，open_id={open_id}')

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user', 'model': User},
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = (
            session.query(Agency)
            .filter_by(ebf_agency_uid=user.ebf_user_agency_uid)
            .first()
        )
        session.close()
        return agency.ebf_agency_uid

    @staticmethod
    def get_user_agency_id(open_id):
        """
        通过用户Open_ID获取用户所属合伙人的记录
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f'获取合伙人记录，open_id={open_id}')

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_user', 'model': User},
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = (
            session.query(Agency)
            .filter_by(ebf_agency_uid=user.ebf_user_agency_uid)
            .first()
        )
        session.close()
        return agency.ebf_agency_id

    @staticmethod
    def get_store_agency(agency_uid):
        """
        通过合伙人ID/UID获取门店合伙人对象

        :param: agency_uid: string or agency_id: int
        :return: store_agency: object

        """
        logger.debug(f'获取所属门店，agency_uid={agency_uid}')

        class GoodsOrder(object):
            pass

        class User(object):
            pass

        class Pay(object):
            pass

        class Agency(object):
            pass

        session = get_db_session(
            [
                {'db_table': 'sdet_order', 'model': GoodsOrder},
                {'db_table': 'ebt_user', 'model': User},
                {'db_table': 'ebt_pay', 'model': Pay},
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        filters = dict()
        if isinstance(agency_uid, int) or re.match('^/d+$', agency_uid):
            filters['ebf_agency_id'] = agency_uid
        else:
            filters['ebf_agency_uid'] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            session.close()
            return None
        # 检查当前用户自己是否为门店
        if agency.ebf_agency_type == AgencyType.STORE:
            logger.info('该合伙人自己就是门店')
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            session.close()
            return None

        # 找到级别里直属合伙人最近的门店
        store_agency = None
        agency_id = agency.ebf_agency_parent_id
        while agency_id and agency_id > 0:
            last_agency = (
                session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            )
            if last_agency:
                agency_id = last_agency.ebf_agency_parent_id
                if last_agency.ebf_agency_type == AgencyType.STORE:
                    store_agency = last_agency
                    break
        session.close()
        return store_agency

    @staticmethod
    def get_store_leader(store_id):
        """
        获取门店店长

        UserHelper.get_store_leader(296)

        :param store_id: 门店编号
        :return: store_leader 门店店长记录
        """

        class Agency:
            pass

        session = get_db_session(
            [
                {'db_table': 'ebt_agency', 'model': Agency},
            ]
        )

        clerks = (
            session.query(Agency)
            .filter_by(
                ebf_agency_parent_id=store_id,
                ebf_agency_type=AgencyType.CLERK,
            )
            .order_by(Agency.ebf_agency_id.asc())
            .all()
        )

        if len(clerks) > 0:
            # 绑定了多个店员，找出店长
            leaders = [w for w in clerks if w.ebf_agency_sub_type == 1]
            n = len(leaders)
            if n == 1:
                # 店长绑定唯一账号
                leader = leaders[0]
                logger.info(f'门店 {store_id} 店长是 {leader.ebf_agency_id}')
            elif n > 1:
                leader = leaders[n - 1]
                logger.error(f'门店 {store_id} 绑定了多个店长！默认最后一个: {leader.ebf_agency_id}')
            else:
                logger.info(f'门店没有绑定店长：store_id={store_id}')
                session.close()
                return None
                # 取消默认第一个店员为店长
                # leader = clerks[0]
                # logger.info(f'门店 {store_id} 店长没有绑定，默认为第一个店员: {leader.ebf_agency_id}')
            session.close()
            return leader
        else:
            # len(clerks) = 0:
            logger.error(f'门店 {store_id} 没有绑定店员账号，没有店长')
            session.close()
            return None

    @staticmethod
    def get_posts_agency(posts_id):
        """
        由点评文章ID获取作者合伙人记录

        :param posts_id: 点评文章ID
        :return agency: 合伙人记录
        """
        db = mongodb_util.db
        posts = db.sdec_posts.find_one({'_id': posts_id})
        if not posts:
            logger.error(f'帖子不存在: {posts_id}')
            return None
        agency_id = posts.get('agency_id')
        if not agency_id:
            logger.error(f'帖子没有合伙人ID: {posts_id}')
            return None

        class Agency(object):
            pass

        session = get_db_session([{'db_table': 'ebt_agency', 'model': Agency}])

        agency = None
        try:
            agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            if not agency:
                logger.error(f'帖子合伙人记录不存在: agency_id={agency_id}')
        except Exception as e:
            logger.exception(e)
        finally:
            session.close()
            return agency

    @staticmethod
    def is_first_new_customer_gift_order(order_id):
        """
        判断是否用户新人礼首单

        AgencyHelper.is_first_new_customer_gift_order(16705862462299458)
        True
        """

        order_types = [OrderType.NORMAL, OrderType.BAR, OrderType.PICKUP_IN_STORE, OrderType.GIFT_CARD]

        class Order(object):
            pass

        session = get_db_session([{'db_table': 'sdet_order', 'model': Order}])

        order = session.query(Order).filter_by(
            sdef_order_id=order_id,
            sdef_order_pay_status=1,
        ).first()
        user_id = order.sdef_order_device_id
        orders = session.query(Order).filter_by(
            sdef_order_device_id=user_id,
            sdef_order_pay_status=1,
        ).filter(
            Order.sdef_order_type.in_(order_types),  # 限定订单类型
            Order.sdef_order_goods.contains(promotion.NEW_CUSTOMER_PROMO_GOODS_ID)  # 限定新人礼订单
        ).order_by(
            Order.sdef_order_pay_time.asc()
        ).all()
        session.close()
        if len(orders) > 0:
            if str(order_id) == str(orders[0].sdef_order_id):
                logger.info(f'is_first_buy: True order_id={order_id}')
                return True
            else:
                logger.info(f'is_first_buy: False order_id={order_id} first_gift_order={orders[0].sdef_order_id}')
                return False
        logger.info(f'is_first_buy: valid type order not exist! order_id={order_id}')
        return False

    @staticmethod
    def is_new_customer_gift_order(order_id):
        """
        判断订单是否为新人礼订单

        AgencyHelper.is_new_customer_gift_order(16456700965493887)
        True
        """

        class Order(object):
            pass

        session = get_db_session([{'db_table': 'sdet_order', 'model': Order}])

        order = session.query(Order).filter_by(
            sdef_order_id=order_id,
            sdef_order_pay_status=1,
        ).first()

        if promotion.NEW_CUSTOMER_PROMO_GOODS_ID in order.sdef_order_goods:
            return True

        return False


def calculate_pre_benefit(order_id):
    """
    计算预收益
    注意所有订单费用是Decimal类型

    calculate_pre_benefit(16472384279275490)
    {'code': 0, 'data': '', 'msg': '请求成功'}

    calculate_pre_benefit(15614422457279805)
    {'code': 0, 'data': '', 'msg': '请求成功'}

    calculate_pre_benefit(16003947132303899)
    {'code': 0, 'data': '', 'msg': '请求成功'}

    :param order_id: 订单号
    :return:
    """

    logger.debug(f'start calculate_pre_benefit: order_id={order_id}')

    class GoodsOrder(object):
        pass

    class Pay(object):
        pass

    class Agency(object):
        pass

    class Benefit(object):
        pass

    class UserAgency(object):
        pass

    class User(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_pay', 'model': Pay},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_user', 'model': User},
        ]
    )

    # 检查订单
    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        session.close()
        return ret_msg(-1, error_message='订单不存在', is_dumps=False)

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        session.close()
        return ret_msg(-1, error_message='订单未支付', is_dumps=False)

    pay_type = pay.sdef_order_pay_type
    if pay_type not in [PayType.WECHAT, PayType.BALANCE]:
        session.close()
        return ret_msg(-1, error_message='目前只支持微信和余额支付的订单计算提成', is_dumps=False)
    if pay_type == PayType.BALANCE:
        if not config.IS_CALCULATE_BALANCE_BENEFIT:
            session.close()
            return ret_msg(-1, error_message='余额支付订单不参与提成计算', is_dumps=False)
    if pay_type == PayType.COUPON:
        session.close()
        return ret_msg(-1, error_message='优惠券支付订单不参与提成计算', is_dumps=False)

    order_type = pay.sdef_order_type
    if order_type == OrderType.PINQU:
        session.close()
        return ret_msg(-1, error_message='取酒订单不参与提成计算', is_dumps=False)

    # 加盟费订单特别跳转处理
    if order_type == OrderType.MEMBER:
        logger.info(f'计算收益: 加盟费订单处理: order_id={order_id}')
        handle_partner_register_order(order_id)
        session.close()
        return ret_msg(is_dumps=False)

    # 新店酬宾活动特别处理
    if promotion.SHOP_OPENING_PROMO_GOODS_ID in pay.sdef_order_goods:
        logger.info(f'计算收益: 新店酬宾活动订单不复核，在tasks.order_paid里一次性处理: order_id={order_id}')
        session.close()
        return ret_msg(is_dumps=False)

    goods_info_arr = json.loads(pay.sdef_order_goods)
    delivery_fee = (
        Decimal(pay.sdef_order_delivery_fee)
        if pay.sdef_order_delivery_fee
        else Decimal('0.00')
    )
    cash_fee, balance_fee, coupon_fee, freight = (
        pay.sdef_order_fee,
        pay.sdef_order_balance_fee,
        pay.sdef_order_coupon_fee,
        pay.sdef_order_delivery_fee,
    )

    # 分润前扣除运费
    if cash_fee - freight >= 0:
        cash_fee -= freight  # 运费不参与分润计算
    else:
        cash_fee = 0
        balance_fee -= freight - cash_fee

    # 计算订单总额
    amount = cash_fee + balance_fee  # 实付金额
    total_amount = cash_fee + balance_fee + coupon_fee  # 订单总额
    remainder = cash_fee
    if total_amount < Decimal(1):
        session.close()
        return ret_msg(error_message='小于1元的测试订单不参与提成计算', is_dumps=False)

    store_id = pay.sdef_order_store_id
    ship_type = pay.sdef_order_ship_type  # 0=快递 1=店内 2=自提 3=外送
    posts_id = pay.sdef_order_recommend_id  # 行家点评文章ID

    # 检查是否已计算预收益 => 改为由底层创建收益订单函数处理， 以便复核分润计算时复用
    # 注意保证同一订单，同一分润账号，同一分润类型的分润记录唯一: 幂等

    # 用户信息
    user_id = pay.sdef_order_device_id
    user = session.query(User).filter_by(ebf_user_id=user_id).first()

    # 直属合伙人信息
    agency_uid = pay.sdef_order_agency_uid
    agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
    agency_id = agency.ebf_agency_id
    agency_type = agency.ebf_agency_type
    agency_sub_type = agency.ebf_agency_sub_type

    # 如果是初级合伙人，就跳过，上溯为上级
    while agency_type == 0:
        logger.info(f"agency_type=0: old_agency_id={agency_id}")
        agency_id = agency.ebf_agency_parent_id
        agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
        agency_uid = agency.ebf_agency_uid
        agency_type = agency.ebf_agency_type
        agency_sub_type = agency.ebf_agency_sub_type

    logger.info(f"agency_type={agency_type} agency_id={agency_id}")

    # 通过合伙人的级别和父级合伙人的ID来查找事业合伙人
    career_agency = AgencyHelper.get_career_agency(agency_uid)
    career_agency_id = (
        career_agency.ebf_agency_id if career_agency else config.DEFAULT_AGENCY_ID
    )
    career_agency_uid = (
        career_agency.ebf_agency_uid if career_agency else config.DEFAULT_AGENCY_UID
    )

    # 事业部上级
    invite_career_agency_id = (
        career_agency.ebf_agency_parent_id
        if career_agency
        else config.DEFAULT_AGENCY_ID
    )
    invite_career_agency = AgencyHelper.get_agency(invite_career_agency_id)
    invite_career_agency_uid = (
        invite_career_agency.ebf_agency_uid
        if invite_career_agency
        else config.DEFAULT_AGENCY_UID
    )

    # 市场部
    super_agency = AgencyHelper.get_super_agency(agency_uid)
    super_agency_uid = (
        super_agency.ebf_agency_uid if super_agency else config.DEFAULT_AGENCY_UID
    )
    super_agency_id = (
        super_agency.ebf_agency_id if super_agency else config.DEFAULT_AGENCY_ID
    )

    # 计算各个层级提成备用 - 注意所有费用数据类型为decimal，rate类型为float
    differ_benefit = BenefitBackend.calculate_differ(
        goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
    )  # 差价=零售价-会员价

    store_differ = BenefitBackend.calculate_store_differ(
        goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
    )  # 门店差价=会员价-进货价

    (
        invite_parent_benefit,
        invite_parent_rate,
    ) = BenefitBackend.calculate_invite_parent_benefit(
        goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
    )

    career_benefit, career_rate = BenefitBackend.calculate_career_benefit(
        goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
    )

    (
        invite_career_benefit,
        invite_career_rate,
    ) = BenefitBackend.calculate_invite_career_benefit(
        goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
    )

    # 计算供应商收益
    if order_type in [OrderType.NORMAL, OrderType.DISTRIBUTOR, OrderType.PINGUI]:
        logger.info(f'计算收益: 开始计算供应商收益: order_id={order_id}, order_type={order_type}')
        supplier_benefits = BenefitBackend.calculate_supplier_benefit(
            goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, order_type
        )
        # 检查订单商品是否为整箱销售
        is_full_pkg = is_goods_full_pkg(goods_info_arr)
        if len(supplier_benefits) == 1 and is_full_pkg:
            # 订单只有单个供应商并且整箱销售，设置订单供应商标志以便自动处理
            supplier_id = supplier_benefits[0].get('supplier', 0)
            pay.sdef_order_supplier_id = supplier_id
            session.commit()
            logger.info(
                f'计算收益: 更新订单供应商: order_id={order_id}, supplier_id={supplier_id}'
            )

            # 计算供应商收益 （只针对单供应商订单）
            for s in supplier_benefits:
                supplier_id = s['supplier']
                if supplier_id:
                    supplier = AgencyHelper.get_agency(supplier_id)
                    if supplier:
                        supplier_uid = supplier.ebf_agency_uid
                        benefit = Decimal(s['cost'])
                        order_fee = benefit
                        rate = 1.0
                        BenefitHelper.create_benefit(
                            BenefitType.SUPPLIER,
                            order_id,
                            supplier_uid,
                            benefit,
                            order_fee,
                            rate,
                            remarks='供应商金额',
                        )
                        remainder -= benefit
                        logger.info(
                            f'计算收益: 创建供应商收益 OK：order_id={order_id}, supplier_uid={supplier_uid}, benefit={benefit}'
                        )
                    else:
                        logger.error(
                            f'计算收益: 创建供应商收益 NG: 供应商不存在！ order_id={order_id}, supplier_id={supplier_id}'
                        )
        else:
            # 多供应商订单，通知平台特别处理
            logger.info(f'计算收益: 更新订单供应商: 多供应商订单由平台处理 order_id={order_id}')

    if order_type == OrderType.PINGUI:
        # 订货订单/拼柜订单
        remarks = '订货订单收益'
        if agency_type == AgencyType.CAREER or (
                agency_type == AgencyType.STORE and agency_sub_type > 2
        ):
            # 合伙人是事业部，直接计算事业部收益
            benefit = career_benefit
            rate = career_rate
            benefit_type = BenefitType.CAREER
            BenefitHelper.create_benefit(
                benefit_type,
                order_id,
                career_agency_uid,
                benefit,
                cash_fee,
                rate,
                remarks,
            )
            remainder -= benefit
            logger.info(
                f'计算收益: 订货订单: 计算事业部收益 order_id={order_id} agency_uid={career_agency_uid} benefit={benefit}'
            )
        else:
            parent_agency_id = agency.ebf_agency_parent_id
            if parent_agency_id:
                parent_agency = AgencyHelper.get_agency(parent_agency_id)
                if parent_agency:
                    # 计算业务员收益(业务员/店员/门店）
                    if (
                            parent_agency.ebf_agency_type == AgencyType.SALES
                            or parent_agency.ebf_agency_type == AgencyType.CLERK
                            or (
                            parent_agency.ebf_agency_type == AgencyType.STORE and parent_agency.ebf_agency_sub_type < 3)
                    ):
                        parent_agency_uid = parent_agency.ebf_agency_uid
                        # 获取服务商业务员分成比率
                        sales_rate: float = career_agency.ebf_agency_sales_rate  # 服务商业务员分成比率
                        if 0.0 <= sales_rate <= 1.0:
                            benefit = career_benefit * Decimal(sales_rate)  # 业务员收益
                            benefit = benefit.quantize(Decimal('0.00'))
                            career_benefit = career_benefit * Decimal(1.0 - sales_rate)  # 事业部收益
                            career_benefit = career_benefit.quantize(Decimal('0.00'))
                            rate = career_rate * sales_rate  # 业务员收益率
                            benefit_type = BenefitType.INVITE_PARENT
                            remarks = '推广收益'
                            BenefitHelper.create_benefit(
                                benefit_type,
                                order_id,
                                parent_agency_uid,
                                benefit,
                                cash_fee,
                                rate,
                                remarks,
                            )
                            remainder -= benefit
                            logger.info(
                                f'计算收益: 推广收益 order_id={order_id} agency_uid={parent_agency_uid} benefit={benefit}'
                            )
                        else:
                            logger.error(
                                f"服务商业务员分成比率错误：sale_rate={sales_rate} agency={agency.ebf_agency_parent_id}")
            if agency.ebf_agency_investor_id:
                # 门店挂靠实体店，给挂靠实体店(investor)事业部收益(挂靠奖)
                real_shop_agency = AgencyHelper.get_agency(
                    agency.ebf_agency_investor_id
                )
                real_shop_agency_uid = real_shop_agency.ebf_agency_uid
                benefit = career_benefit
                rate = career_rate
                benefit_type = BenefitType.INVESTOR
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    real_shop_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 订货订单: 计算门店挂靠收益 order_id={order_id} agency_uid={real_shop_agency_uid} benefit={benefit}'
                )
            else:
                # 计算所属事业部收益
                benefit_type = BenefitType.CAREER
                benefit = career_benefit
                rate = career_rate
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    career_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 订货订单: 计算事业部收益 order_id={order_id} agency_uid={career_agency_uid} benefit={benefit}'
                )

        # 计算事业部上级的收益
        if invite_career_agency and invite_career_agency.ebf_agency_investor_id:
            # 处理夏雪和朋友共同发展实体店的特别情况：平分事业部上级收益
            invite_career_investor = AgencyHelper.get_agency(
                invite_career_agency.ebf_agency_investor_id
            )
            invite_career_investor_uid = invite_career_investor.ebf_agency_uid
            benefit_type = BenefitType.INVITE_INVESTOR
            benefit = invite_career_benefit * Decimal(0.5)
            rate = invite_career_rate / 2
            BenefitHelper.create_benefit(
                benefit_type,
                order_id,
                invite_career_investor_uid,
                benefit,
                cash_fee,
                rate,
                remarks,
            )
            remainder -= benefit
            logger.info(
                f'计算收益: 订货订单: 计算事业部上级投资者收益 order_id={order_id} agency_uid={invite_career_investor_uid} benefit={benefit}'
            )
            # 处理夏雪和朋友共同发展实体店的特别情况：事业部上级收益减半
            benefit_type = BenefitType.INVITE_CAREER
            benefit = invite_career_benefit * Decimal(0.5)
            rate = invite_career_rate / 2
            BenefitHelper.create_benefit(
                benefit_type,
                order_id,
                invite_career_agency_uid,
                benefit,
                cash_fee,
                rate,
                remarks,
            )
            remainder -= benefit
            logger.info(
                f'计算收益: 订货订单: 计算事业部上级收益 order_id={order_id} agency_uid={career_agency_uid} benefit={benefit}'
            )
        else:
            benefit_type = BenefitType.INVITE_CAREER
            benefit = invite_career_benefit
            rate = invite_career_rate
            BenefitHelper.create_benefit(
                benefit_type,
                order_id,
                invite_career_agency_uid,
                benefit,
                cash_fee,
                rate,
                remarks,
            )
            remainder -= benefit
            logger.info(
                f'计算收益: 订货订单: 计算事业部上级收益 order_id={order_id} agency_uid={invite_career_agency_uid} benefit={benefit}'
            )

        # 计算超级事业部收益（公司市场部）
        super_agency = AgencyHelper.get_super_agency(agency_uid)
        if super_agency:
            # 如果超级事业部存在，计算分润（金额暂按事业部上级计算）
            super_agency_uid = super_agency.ebf_agency_uid
            super_agency_id = super_agency.ebf_agency_id
            rate = 0.0225  # cost x 75% x 3%
            benefit = (cash_fee - delivery_fee) * Decimal(rate)
            BenefitHelper.create_benefit(
                BenefitType.SUPER_CAREER,
                order_id,
                super_agency_uid,
                benefit,
                total_amount,
                rate,
            )
            remainder -= benefit
            logger.info(
                f'计算收益: 超级事业部收益: order_id={order_id}, super_agency_id={super_agency_id}, benefit={benefit}'
            )
        else:
            logger.info(f'计算收益: 无超级事业部: order_id={order_id}')

        # 记录平台收益
        BenefitHelper.create_benefit(0, order_id, 0, remainder, total_amount, rate)
        logger.info(f'计算收益：平台收益 order_id={order_id}, benefit={remainder}')
        if remainder < 0:
            logger.error(f'计算收益：平台收益<0 order_id={order_id}, benefit={remainder}')

    # 小酒馆订单-店内消费
    elif order_type in [OrderType.BAR, OrderType.PICKUP_IN_STORE]:
        # if promotion.BEER_PROMOTION_GOODS_ID in pay.sdef_order_goods:
        #     # 1元啤酒试饮活动
        #     logger.info(f'计算收益: 啤酒试饮活动 order_id={order_id}')
        #     benefit = promotion.BEER_PROMOTION_BENEFIT
        #     rate = float(1.0)
        #     remarks = "啤酒试饮活动"
        #     benefit_type = BenefitType.STORE_FREECARD
        #     bar = AgencyHelper.get_agency(store_id)
        #     bar_uid = bar.ebf_agency_uid
        #     BenefitHelper.create_benefit(
        #         benefit_type, order_id, bar_uid, benefit, total_amount, rate, remarks
        #     )
        #     logger.info(
        #         f'计算收益：啤酒试饮活动 小酒馆收益 order_id={order_id}, benefit={benefit}, rate={rate}, cash={cash_fee}, balance={balance_fee}, coupon={coupon_fee}'
        #     )
        # else:
        # 合并计算小酒馆/门店自提订单收益
        rate = float(benefit / total_amount)
        remarks = "店内订单收款"
        benefit_type = BenefitType.STORE_FREECARD
        bar = AgencyHelper.get_agency(store_id)
        bar_uid = bar.ebf_agency_uid
        BenefitHelper.create_benefit(
            benefit_type, order_id, bar_uid, benefit, total_amount, rate, remarks
        )
        logger.info(
            f'计算收益：小酒馆收益 order_id={order_id}, benefit={benefit}, rate={rate}, cash={cash_fee}, balance={balance_fee}, coupon={coupon_fee}'
        )
        if remainder < 0:
            logger.error(
                f'计算收益：小酒馆收益<0 order_id={order_id}, benefit={benefit}, rate={rate}, cash={cash_fee}, balance={balance_fee}, coupon={coupon_fee}'
            )

    # 线上/外送/高级门店平台代发订单
    elif (
            store_id == 0
            or ship_type == 3
            or agency_type == AgencyType.STORE
            and agency_sub_type != 0
    ):
        # 计算线上/外送订单预估收益(外送订单收益按线上比例计算 20190530) + 计算高级门店订单收益 20200424
        if store_id == 0:
            logger.info(f'计算收益: 线上订单预收益：order_id={order_id}')
        else:
            logger.info(f'计算收益: 外送订单预收益：order_id={order_id}')

        # 高级门店订单处理（烟酒行）- 2020-02-20 增加店员和业务员分润 - 20220617
        if (agency_type == AgencyType.STORE and agency_sub_type != 0) or agency_type == AgencyType.CLERK or agency_type == AgencyType.SALES:
            remarks = '高级门店线上订单收益'
            logger.info(f'计算收益: 开始计算高级门店线上订单收益：order_id={order_id}')

            # 扣除进货价
            cost = Decimal('0.00')
            for g in goods_info_arr:
                cost += Decimal(str(g['goods_pin_price'])) * Decimal(str(g['count']))

            if not cost > Decimal('0.00'):
                logger.error(
                    f'计算收益: 高级门店线上订单收益：进货价不大于0: pin_price={cost} order_id={order_id}'
                )
                session.close()
                return ret_msg(is_dumps=False)

            parent_agency_id = agency.ebf_agency_parent_id
            if parent_agency_id:
                # 计算服务商业务员收益(包括门店推荐门店）
                parent_agency = AgencyHelper.get_agency(parent_agency_id)
                if parent_agency:
                    parent_agency_id = parent_agency.ebf_agency_id
                    parent_agency_uid = parent_agency.ebf_agency_uid
                    if (
                            parent_agency.ebf_agency_type == AgencyType.SALES
                            or parent_agency.ebf_agency_type == AgencyType.CLERK
                    ):
                        # 服务商业务员/店员推荐门店
                        sales_rate = career_agency.ebf_agency_sales_rate
                        if 0.0 <= sales_rate <= 1.0:
                            benefit = career_benefit * Decimal(sales_rate)  # 业务员收益
                            benefit = benefit.quantize(Decimal('0.00'))
                            career_benefit = career_benefit * Decimal(1.0 - sales_rate)  # 修正事业部收益
                            career_benefit = career_benefit.quantize(Decimal('0.00'))
                            rate = career_rate * sales_rate  # 业务员收益率
                            benefit_type = BenefitType.INVITE_PARENT
                            remarks = '推广收益'
                            BenefitHelper.create_benefit(
                                benefit_type,
                                order_id,
                                parent_agency_uid,
                                benefit,
                                cash_fee,
                                rate,
                                remarks,
                            )
                            remainder -= benefit
                            logger.info(
                                f'计算收益: 推广收益 order_id={order_id} agency_uid={parent_agency_uid} benefit={benefit}'
                            )
                        else:
                            logger.error(f"服务商业务员分成比率错误：sale_rate={sales_rate} agency={parent_agency_id}")
                    elif (parent_agency.ebf_agency_type == AgencyType.STORE and parent_agency.ebf_agency_sub_type < 3):
                        # 门店推荐门店 - 20221005
                        benefit = invite_parent_benefit
                        rate = invite_parent_rate
                        benefit_type = BenefitType.INVITE_PARENT
                        remarks = '推广收益'
                        BenefitHelper.create_benefit(
                            benefit_type,
                            order_id,
                            parent_agency_uid,
                            benefit,
                            cash_fee,
                            rate,
                            remarks,
                        )
                        remainder -= benefit
                        career_benefit -= benefit  # 服务商收益扣减门店推荐奖
                        logger.info(
                            f'计算收益: 推广收益 order_id={order_id} agency_uid={parent_agency_uid} benefit={benefit}'
                        )
                    else:
                        pass  # 非服务商业务员/店员或门店推荐门店
            if agency.ebf_agency_investor_id:
                # 门店挂靠实体店，给挂靠实体店挂靠收益（事业部收益）
                real_shop_agency = AgencyHelper.get_agency(
                    agency.ebf_agency_investor_id
                )
                real_shop_agency_uid = real_shop_agency.ebf_agency_uid
                benefit = career_benefit
                rate = career_rate
                benefit_type = BenefitType.INVESTOR
                remarks = '门店挂靠收益'
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    real_shop_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 门店挂靠实体店收益 order_id={order_id} agency_uid={real_shop_agency_uid} benefit={benefit}'
                )
            else:
                # 计算所属事业部收益
                benefit_type = BenefitType.CAREER
                benefit = career_benefit
                rate = career_rate
                remarks = '高级门店线上订单事业部收益'
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    career_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 计算事业部收益 order_id={order_id} agency_uid={career_agency_uid} benefit={benefit}'
                )

            # 计算事业部上级的收益
            if invite_career_agency and invite_career_agency.ebf_agency_investor_id:
                # 处理夏雪和朋友共同发展实体店的特别情况：平分事业部上级收益
                invite_career_investor = AgencyHelper.get_agency(
                    invite_career_agency.ebf_agency_investor_id
                )
                invite_career_investor_uid = invite_career_investor.ebf_agency_uid
                benefit_type = BenefitType.INVITE_INVESTOR
                benefit = invite_career_benefit * Decimal(0.5)
                rate = invite_career_rate / 2
                remarks = '实体店投资收益'
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    invite_career_investor_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 计算事业部上级投资者收益 order_id={order_id} agency_uid={invite_career_investor_uid} benefit={benefit}'
                )
                # 处理夏雪和朋友共同发展实体店的特别情况：事业部上级收益减半
                benefit_type = BenefitType.INVITE_CAREER
                benefit = invite_career_benefit * Decimal(0.5)
                rate = invite_career_rate / 2
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    invite_career_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 计算事业部上级收益 order_id={order_id} agency_uid={career_agency_uid} benefit={benefit}'
                )
            else:
                benefit_type = BenefitType.INVITE_CAREER
                benefit = invite_career_benefit
                rate = invite_career_rate
                remarks = '事业部上级收益'
                BenefitHelper.create_benefit(
                    benefit_type,
                    order_id,
                    invite_career_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 计算事业部上级收益 order_id={order_id} agency_uid={invite_career_agency_uid} benefit={benefit}'
                )

            # 计算线上门店收益
            benefit = cash_fee - cost

            rate = float(benefit / cash_fee)
            if benefit <= 0:
                logger.error(
                    f'计算收益: 高级门店线上订单收益: 门店收益 <= 0: order_id={order_id}: 订单金额{cash_fee}-进货成本{cost}=收益{benefit}'
                )
                session.close()
                return ret_msg(is_dumps=False)

            # 计算门店店员/业务员订单
            if agency_type == AgencyType.CLERK or agency_type == AgencyType.SALES:
                # 门店为店员/业务员上级
                parent_agency = AgencyHelper.get_agency(agency.ebf_agency_parent_id)
                sales_rate = parent_agency.ebf_agency_sales_rate
                sales_benefit = benefit * Decimal(sales_rate).quantize(Decimal('0.00'))
                sales_benefit_rate = float(sales_benefit / cash_fee)
                remarks = '门店业务员线上订单收益'
                BenefitHelper.create_benefit(
                    BenefitType.PARENT,
                    order_id,
                    agency_uid,
                    sales_benefit,
                    cash_fee,
                    sales_benefit_rate,
                    remarks,
                )
                remainder -= sales_benefit

                # 修正门店收益
                benefit -= sales_benefit  # 门店收益扣减业务员收益
                rate = float(benefit / cash_fee)  # 重新计算收益率
                remarks = '高级门店线上订单收益'
                logger.info(
                    f'计算收益: 高级门店线上订单收益: 门店 order_id={order_id} store_id={agency_id} benefit={benefit} rate={rate}'
                )
                BenefitHelper.create_benefit(
                    BenefitType.DIFFER,
                    order_id,
                    parent_agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit
            else:
                remarks = '高级门店线上订单收益'
                logger.info(
                    f'计算收益: 高级门店线上订单收益: 门店 order_id={order_id} store_id={agency_id} benefit={benefit} rate={rate}'
                )
                BenefitHelper.create_benefit(
                    BenefitType.DIFFER,
                    order_id,
                    agency_uid,
                    benefit,
                    cash_fee,
                    rate,
                    remarks,
                )
                remainder -= benefit

            # 计算超级事业部收益（公司市场部）
            super_agency = AgencyHelper.get_super_agency(agency_uid)
            if super_agency:
                # 如果超级事业部存在，计算分润（金额暂按事业部上级计算）
                super_agency_uid = super_agency.ebf_agency_uid
                super_agency_id = super_agency.ebf_agency_id
                rate = 0.0225  # 市场部：扣除运营中心费用后的3%=75%x3%=2.25% 20210219
                benefit = cost * Decimal(rate)
                BenefitHelper.create_benefit(
                    BenefitType.SUPER_CAREER,
                    order_id,
                    super_agency_uid,
                    benefit,
                    cost,
                    rate,
                )
                remainder -= benefit
                logger.info(
                    f'计算收益: 超级事业部收益: order_id={order_id}, super_agency_id={super_agency_id}, benefit={benefit}'
                )
            else:
                logger.info(f'计算收益: 无超级事业部: order_id={order_id}')

            # 记录平台收益
            benefit = remainder
            rate = float(remainder / total_amount)
            BenefitHelper.create_benefit(0, order_id, 0, benefit, total_amount, rate)
            logger.info(
                f'计算收益：平台收益 order_id={order_id}, benefit={benefit}, rate={rate}, cash={cash_fee}, balance={balance_fee}, coupon={coupon_fee}'
            )
            if remainder < 0:
                logger.error(
                    f'计算收益：平台收益<0 order_id={order_id}, benefit={benefit}, rate={rate}, cash={cash_fee}, balance={balance_fee}, coupon={coupon_fee}'
                )

    # 计算原线下门店店内消费订单收益 ===========================================================
    elif store_id > 0 and ship_type != 3:
        # 计算店内消费订单分润
        logger.info(f'计算收益: 线下订单预收益：order_id={order_id}, store_id={store_id}')

        # 特别处理促销订单
        is_promotion_only = False
        # 取消店员促销 - lijim 20190902
        # is_promotion = is_promotion_order(order_id)
        is_promotion = False
        if is_promotion:
            logger.info(f'计算收益: 促销订单 order_id={order_id}')
            promotion_fee = promotion.PROMOTION_GOODS_PRICE
            if amount == promotion_fee:
                logger.info(f'计算收益: 订单只有促销商品: order_id={order_id}')
                is_promotion_only = True
                # 扣除促销商品金额后计算收益
                cash_fee = Decimal('0.00')
                balance_fee = Decimal('0.00')
                coupon_fee = promotion_fee
            elif cash_fee >= promotion_fee:
                # 扣除促销商品金额后计算收益
                cash_fee -= promotion_fee
                coupon_fee += promotion_fee
            elif balance_fee + cash_fee > promotion_fee:
                # 实付金额可以扣减促销商品金额后计算收益
                balance_fee = balance_fee + cash_fee - promotion_fee
                coupon_fee += promotion_fee
                cash_fee = Decimal('0.00')  # 先把现金扣除完
            else:
                # 用券情况下，promotion_fee > (balance_fee + cash_fee)
                coupon_fee = total_amount
                cash_fee = Decimal('0.00')
                balance_fee = Decimal('0.00')

        store_agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
        if store_agency:
            # 计算服务员分润
            if agency_type == AgencyType.CLERK:
                # 如果客户就在服务员名下， 计算店员线下订单分润
                benefit_type = BenefitType.CLERK_OFFLINE
                benefit, rate = BenefitBackend.calculate_benefit(
                    goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, benefit_type
                )
                if is_promotion_only:
                    logger.info(
                        f'计算收益: 店员线下促销收益: order_id={order_id}, agency_id={agency_id}'
                    )
                    benefit = promotion.PROMOTION_BENEFIT
                    rate = float(benefit / amount)
                elif is_promotion:
                    # 促销订单特别处理
                    logger.info(
                        f'计算收益: 店员线下促销收益: order_id={order_id}, agency_id={agency_id}'
                    )
                    benefit = benefit + promotion.PROMOTION_BENEFIT
                    rate = float(benefit / amount)
                else:
                    pass
                logger.info(
                    f'计算收益: 店员线下订单收益：order_id={order_id} agency_uid={agency_uid}'
                )
                BenefitHelper.create_normal_agency_benefit(
                    order_id, agency_uid, benefit, total_amount, rate
                )
            else:
                # 门店直属订单计算店长分润
                leader = AgencyHelper.get_store_leader(store_id)
                if leader:
                    leader_agency_id = leader.ebf_agency_id
                    leader_agency_uid = leader.ebf_agency_uid
                    benefit_type = BenefitType.CLERK_OFFLINE
                    benefit, rate = BenefitBackend.calculate_benefit(
                        goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, benefit_type
                    )
                    if is_promotion:
                        # 促销订单特别处理
                        logger.info(
                            f'计算收益: 店长线下促销收益: order_id={order_id}, agency_id={leader_agency_id}'
                        )
                        benefit = benefit + promotion.PROMOTION_BENEFIT
                        rate = float(benefit / amount)
                    else:
                        pass
                    logger.info(
                        f'计算收益: 店长线下订单收益：order_id={order_id} agency_id={leader_agency_id}'
                    )
                    BenefitHelper.create_normal_agency_benefit(
                        order_id, leader_agency_uid, benefit, total_amount, rate
                    )
                else:
                    logger.error(
                        f'计算收益: 门店没有店长！order_id={order_id} store_id={store_id}'
                    )

            # 计算终端门店分润
            store_agency_uid = store_agency.ebf_agency_uid
            benefit_type = BenefitType.STORE_OFFLINE
            logger.info(
                f'计算收益: 门店线下订单收益：order_id={order_id}, agency_uid={store_agency_uid}, benefit_type={benefit_type}'
            )

            store_create_time = store_agency.ebf_agency_create_time
            if store_create_time and store_create_time > datetime.datetime(2019, 9, 15):
                # 20190915起新门店分润降为20%
                rate = 0.2  # 20%
                benefit = cash_fee * Decimal(str(rate))
                benefit = benefit.quantize(Decimal('1.00'))
            else:
                benefit, rate = BenefitBackend.calculate_benefit(
                    goods_info_arr, cash_fee, balance_fee, coupon_fee, delivery_fee, benefit_type
                )
            if is_promotion:
                # 补上促销品的分润
                benefit += promotion.PROMOTION_BENEFIT_STORE
                rate = float(benefit / amount)

            BenefitHelper.create_normal_agency_benefit(
                order_id, store_agency_uid, benefit, total_amount, rate
            )

            # 计算所属门店推荐人分润
            store_recommender_agency_id = store_agency.ebf_agency_parent_id
            if store_recommender_agency_id != 0:
                store_recommender_agency = (
                    session.query(Agency)
                    .filter_by(ebf_agency_id=store_recommender_agency_id)
                    .first()
                )
                if store_recommender_agency:
                    logger.info(
                        f'计算收益: 门店推荐人线下订单收益：order_id={order_id}, agency_id={store_recommender_agency_id}'
                    )
                    store_recommender_agency_uid = (
                        store_recommender_agency.ebf_agency_uid
                    )
                    benefit_type = BenefitType.INVITE_STORE_OFFLINE

                    if is_promotion_only:
                        benefit = promotion.PROMOTION_BENEFIT_OTHERS
                        rate = promotion.PROMOTION_BENEFIT_OTHERS_RATE
                    else:
                        benefit, rate = BenefitBackend.calculate_benefit(
                            goods_info_arr,
                            cash_fee,
                            balance_fee,
                            coupon_fee,
                            delivery_fee,
                            benefit_type,
                        )

                    BenefitHelper.create_normal_agency_benefit(
                        order_id,
                        store_recommender_agency_uid,
                        benefit,
                        total_amount,
                        rate,
                    )

                    # 计算所属门店推荐人上级分润
                    store_recommender_invite_agency_id = (
                        store_recommender_agency.ebf_agency_parent_id
                    )
                    if store_recommender_invite_agency_id != 0:
                        store_recommender_invite_agency = (
                            session.query(Agency)
                            .filter_by(ebf_agency_id=store_recommender_invite_agency_id)
                            .first()
                        )
                        if store_recommender_invite_agency:
                            logger.info(
                                f'计算收益: 门店推荐人上级线下订单收益：order_id={order_id}, agency_id={store_recommender_invite_agency_id}'
                            )
                            store_recommender_invite_agency_uid = (
                                store_recommender_invite_agency.ebf_agency_uid
                            )

                            benefit_type = BenefitType.INVITE_INVITE_STORE_OFFLINE

                            if is_promotion_only:
                                benefit = promotion.PROMOTION_BENEFIT_OTHERS
                                rate = promotion.PROMOTION_BENEFIT_OTHERS_RATE
                            else:
                                benefit, rate = BenefitBackend.calculate_benefit(
                                    goods_info_arr,
                                    cash_fee,
                                    balance_fee,
                                    coupon_fee,
                                    delivery_fee,
                                    benefit_type,
                                )

                            BenefitHelper.create_invite_normal_agency_benefit(
                                order_id,
                                store_recommender_invite_agency_uid,
                                benefit,
                                total_amount,
                                rate,
                            )

                            # 计算运营商上级分润(运营商介绍运营商的情况)
                            # 门店上级的上级为事业部而且他的上级为事业部
                            if (
                                    store_recommender_invite_agency.ebf_agency_type
                                    == AgencyType.CAREER
                            ):
                                store_career_agency_id = (
                                    store_recommender_invite_agency.ebf_agency_parent_id
                                )
                                if store_career_agency_id != 0:
                                    store_career_agency = (
                                        session.query(Agency)
                                        .filter_by(ebf_agency_id=store_career_agency_id)
                                        .first()
                                    )
                                    if (
                                            store_career_agency
                                            and store_career_agency.ebf_agency_type
                                            == AgencyType.CAREER
                                    ):
                                        logger.info(
                                            f'计算收益: 计算门店推荐人上级上级线下订单收益：order_id={order_id}, agency_id={store_career_agency_id}'
                                        )
                                        store_career_agency_uid = (
                                            store_career_agency.ebf_agency_uid
                                        )
                                        benefit_type = (
                                            BenefitType.INVITE_INVITE_STORE_OFFLINE
                                        )
                                        if is_promotion_only:
                                            benefit = promotion.PROMOTION_BENEFIT_OTHERS
                                            rate = (
                                                promotion.PROMOTION_BENEFIT_OTHERS_RATE
                                            )
                                        else:
                                            (
                                                benefit,
                                                rate,
                                            ) = BenefitBackend.calculate_benefit(
                                                goods_info_arr,
                                                cash_fee,
                                                balance_fee,
                                                coupon_fee,
                                                delivery_fee,
                                                benefit_type,
                                            )
                                        BenefitHelper.create_invite_career_agency_benefit(
                                            order_id,
                                            store_career_agency_uid,
                                            benefit,
                                            total_amount,
                                            rate,
                                        )
                                    else:
                                        logger.info(
                                            f'计算收益: 门店推荐人上级上级不存在！order_id={order_id}, agency_id={store_career_agency_id}'
                                        )
                                else:
                                    logger.info(
                                        f'计算收益: 门店推荐人上级上级不存在！order_id={order_id}, agency_id={store_career_agency_id}'
                                    )
                            else:
                                logger.info(
                                    f'计算收益: 门店推荐人上级不是事业部 order_id={order_id}, agency_id={store_recommender_invite_agency}'
                                )
                        else:
                            logger.error(
                                f'计算收益: 门店推荐人上级记录不存在! order_id={order_id} agency_id={store_recommender_invite_agency_id}'
                            )
                    else:
                        logger.error(f'计算收益: 门店推荐人没有上级! order_id={order_id}')
                else:
                    logger.error(
                        f'计算收益: 门店推荐人记录不存在! order_id={order_id} agency_id={store_recommender_agency_id}'
                    )
            else:
                logger.error(f'计算收益: 门店没有推荐人! order_id={order_id}')

            # 计算所属门店投资方分润
            store_investor_agency_id = store_agency.ebf_agency_investor_id
            if store_investor_agency_id != 0:
                store_investor_agency = (
                    session.query(Agency)
                    .filter_by(ebf_agency_id=store_investor_agency_id)
                    .first()
                )
                if store_investor_agency:
                    logger.info(
                        f'计算收益: 门店投资方线下订单收益：order_id={order_id}, agency_id={store_investor_agency_id}'
                    )
                    store_investor_agency_uid = store_investor_agency.ebf_agency_uid

                    benefit_type = BenefitType.INVESTOR_OFFLINE

                    if is_promotion_only:
                        benefit = promotion.PROMOTION_BENEFIT_OTHERS
                        rate = promotion.PROMOTION_BENEFIT_OTHERS_RATE
                    else:
                        benefit, rate = BenefitBackend.calculate_benefit(
                            goods_info_arr,
                            cash_fee,
                            balance_fee,
                            coupon_fee,
                            delivery_fee,
                            benefit_type,
                        )

                    BenefitHelper.create_career_agency_benefit(
                        order_id, store_investor_agency_uid, benefit, total_amount, rate
                    )

                    # 计算所属门店投资方上级分润
                    store_investor_invite_agency_id = (
                        store_investor_agency.ebf_agency_parent_id
                    )
                    if store_investor_invite_agency_id != 0:
                        store_investor_invite_agency = (
                            session.query(Agency)
                            .filter_by(ebf_agency_id=store_investor_invite_agency_id)
                            .first()
                        )
                        if store_investor_invite_agency:
                            logger.info(
                                f'计算收益: 门店投资方上级线下订单收益：order_id={order_id}, agency_id={store_investor_invite_agency_id}'
                            )
                            store_investor_invite_agency_uid = (
                                store_investor_invite_agency.ebf_agency_uid
                            )

                            benefit_type = BenefitType.INVITE_INVESTOR_OFFLINE

                            if is_promotion_only:
                                benefit = promotion.PROMOTION_BENEFIT_OTHERS
                                rate = promotion.PROMOTION_BENEFIT_OTHERS_RATE
                            else:
                                benefit, rate = BenefitBackend.calculate_benefit(
                                    goods_info_arr,
                                    cash_fee,
                                    balance_fee,
                                    coupon_fee,
                                    delivery_fee,
                                    benefit_type,
                                )

                            BenefitHelper.create_invite_career_agency_benefit(
                                order_id,
                                store_investor_invite_agency_uid,
                                benefit,
                                total_amount,
                                rate,
                            )
                        else:
                            logger.error(
                                f'计算收益: 门店投资方上级记录不存在! order_id={order_id} agency_id={store_investor_invite_agency_id}'
                            )
                    else:
                        logger.error(f'计算收益: 门店投资方没有上级! order_id={order_id}')
                else:
                    logger.error(
                        f'计算收益: 门店投资方记录不存在! order_id={order_id} agency_id={store_investor_agency_id}'
                    )
            else:
                logger.error(f'计算收益: 门店没有投资方! order_id={order_id}')

            # （20190915起新门店分润降为20%）新门店订单给发卡合伙人分润5%
            store_create_time = store_agency.ebf_agency_create_time
            if store_create_time and store_create_time > datetime.datetime(2019, 9, 15):
                user_agency = AgencyHelper.get_user_bind_agency(
                    pay.sdef_order_device_id
                )
                if user_agency:
                    user_agency_id = user_agency.ebf_agency_id
                    user_agency_uid = user_agency.ebf_agency_uid
                    user_agency_type = user_agency.ebf_agency_type
                    user_agency_subtype = user_agency.ebf_agency_sub_type

                    if (
                            user_agency_type == AgencyType.SALES
                            and user_agency_subtype == 3
                    ):
                        benefit = cash_fee * Decimal('0.05')  # 5%
                        benefit = benefit.quantize(Decimal('1.00'))
                        rate = 0.05  # 5%
                        BenefitHelper.create_normal_agency_benefit(
                            order_id, user_agency_uid, benefit, total_amount, rate
                        )
                        logger.info(
                            f'计算收益: 体验卡发卡商户收益：order_id={order_id}, agency_id={user_agency_id}'
                        )
        else:
            logger.error(f'计算收益: 门店记录不存在！order_id={order_id}, store_id={store_id}')

    # 例外情况 ====================================================================
    else:
        logger.error(f'计算收益: 未知订单类型 order_id={order_id}')
    logger.debug(f'complete calculate_pre_benefit: order_id={order_id}')
    session.close()
    return ret_msg(is_dumps=False)


def calculate_benefit(order_id):
    """
    计算合伙人收益

    :param order_id:
    :return:
    """

    class GoodsOrder(object):
        pass

    class Pay(object):
        pass

    class Benefit(object):
        pass

    class CouponUser(object):
        pass

    class Coupon(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_pay', 'model': Pay},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
            {'db_table': 'ebt_coupon', 'model': Coupon},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        session.close()
        return ret_msg(-1, error_message='订单不存在', is_dumps=False)

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        session.close()
        return ret_msg(-1, error_message='订单未支付', is_dumps=False)

    if pay.sdef_order_status not in [OrderStatus.RECEIVED, OrderStatus.COMPLETE]:
        session.close()
        return ret_msg(-1, error_message='已收货或完成的订单才能计算提成', is_dumps=False)

    if pay.sdef_order_pay_type not in [PayType.WECHAT, PayType.BALANCE]:
        session.close()
        return ret_msg(0, error_message='目前只支持微信和余额支付的订单计算提成', is_dumps=False)

    if pay.sdef_order_pay_type == PayType.BALANCE:
        if not config.IS_CALCULATE_BALANCE_BENEFIT:
            session.close()
            return ret_msg(error_message='余额不参与提成计算', is_dumps=False)

    # 检查是否已经计算提成了
    old_pay = session.query(Benefit).filter_by(order_id=order_id, is_finish=1).first()
    if old_pay:
        logger.info(f'已计算提成: order_id={order_id}')
        session.close()
        return ret_msg(error_message='已计算提成', is_dumps=False)

    BenefitHelper.create_complete_order(order_id)
    ret = ret_msg(is_dumps=False)
    logger.info(f'成功计算提成：order_id={order_id}')
    flag = False
    filters = dict(
        user_id=pay.sdef_order_device_id, order_id=order_id, status=0, is_active=0
    )
    if pay.sdef_order_store_id > 0 and pay.sdef_order_ship_type > 0:
        pay.sdef_order_status = OrderStatus.COMPLETE
        flag = True
        logger.info(f'修改门店订单状态为完成order_id={order_id}')

    cus = session.query(CouponUser).filter_by(**filters).all()
    for cu in cus:
        cu.is_active = 1
        now = datetime.datetime.now()
        cu.effect_date = now
        cp_id = cu.coupon_id
        cp = session.query(Coupon).filter_by(id=cp_id).first()
        if not cp:
            logger.error(f'Coupon表无此优惠券：order_id={order_id} cp_id={cp_id}')
            continue
        days = cp.effective_days
        expiry_date = (now + datetime.timedelta(days=days)).replace(
            hour=23, minute=59, second=58
        )
        cu.expiry_date = expiry_date
        minus_time = int((expiry_date - now).total_seconds())
        if not add_mq_task(order_id, message_type=5, delay=minus_time):
            logger.error(f'添加优惠券在规定的时间后过期到任务队列失败：order_id={order_id}')

        if not flag:
            flag = True

    if flag:
        session.commit()
    session.close()
    return ret


def send_benefit_notice(order_id):
    """
    通知收益合伙人

    :param: order_id
    :return:
    """

    class GoodsOrder(object):
        pass

    class Benefit(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class User(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_user', 'model': User},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'nofity_benefit_agency: 订单不存在: {order_id}')
        session.close()
        return

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.error(f'nofity_benefit_agency: 订单未支付 {order_id}')
        session.close()
        return

    store_id = pay.sdef_order_store_id
    if store_id == 0:
        # 线上订单收益通知
        user = (
            session.query(User).filter_by(ebf_user_id=pay.sdef_order_device_id).first()
        )
        name = user.ebf_user_nickname if user else None
        if name == '未关注' or name is None:
            name = ''
            first = f'您有一个来自【线上商城】的新订单，预估收益如下：'
        else:
            first = f'您的朋友{name}下了一个新订单，预估收益如下：'
    else:
        # 线下订单收益通知
        store = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
        if store:
            name = store.ebf_agency_name
            if name is None:
                name = ''
                first = f'您有一个来自门店的新订单，预估收益如下：'
            else:
                first = f'您的朋友{name}下了一个新订单，预估收益如下：'
        else:
            logger.error(f'NG: 门店 store_id={store_id} 记录不存在！')
            session.close()
            return
    try:
        benefits = session.query(Benefit).filter_by(order_id=order_id)
        if benefits:
            for b in benefits:
                agency_uid = b.agency_uid
                agency = (
                    session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
                )
                if not agency:
                    continue

                user_agency = (
                    session.query(UserAgency)
                    .filter_by(ebf_agency_id=agency.ebf_agency_id)
                    .first()
                )
                agency_open_id = (
                    user_agency.ebf_ua_bind_user_id if user_agency else None
                )
                agency_type = agency.ebf_agency_type
                # 异步发送模版消息-直属高级合伙人
                if agency_open_id:
                    if pay.sdef_order_coupon_fee > Decimal('0'):
                        order_fee = (
                            str(b.order_fee.quantize(Decimal('1.00'))) + '元【优惠订单】'
                        )
                    elif is_promotion_order(order_id):
                        order_fee = (
                            str(b.order_fee.quantize(Decimal('1.00'))) + '元【促销订单】'
                        )
                    else:
                        order_fee = str(b.order_fee.quantize(Decimal('1.00'))) + '元'

                    tasks.send_order_benefit_notice.delay(
                        first,
                        order_id,
                        order_fee,
                        str(b.fee.quantize(Decimal('1.00'))),
                        agency_open_id,
                        b.create_time.strftime('%Y{y}%m{m}%d{d} %H:%M:%S').format(
                            y='年', m='月', d='日'
                        ),
                        agency_type,
                    )
    except Exception as e:
        logger.exception(e)
        logger.error(f'NG: send_benefit_notice: order_id: {order_id}')
    else:
        logger.info(f'OK: send_benefit_notice: order_id: {order_id}')


def send_new_order_notice(order_id):
    """
    新订单通知门店和店员

    send_store_order_notice(15573004468645913)

    :param: order_id
    :return:
    """

    class GoodsOrder(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class User(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_user', 'model': User},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'send_store_order_notice: 订单不存在 {order_id}')
        session.close()
        return

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.error(f'send_store_order_notice: 订单未支付 {order_id}')
        session.close()
        return

    # 通知内容
    first = '你有一个新订单, 请及时处理'

    goods = ''
    goods_info = json.loads(pay.sdef_order_goods)

    for g in goods_info:
        goods_name = g['goods_name']
        count = Decimal(g['count'])
        goods += f'{goods_name} x {count} \n'

    time = (
        (pay.sdef_order_pay_time).strftime('%Y-%m-%d %H:%M:%S')
        if pay.sdef_order_pay_time
        else ''
    )
    url = f'https://{DOMAIN}/user/account'
    remark = f''
    address = '线上商城'

    store_id = pay.sdef_order_store_id
    if store_id > 0:
        # 线下订单通知
        store_agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
        if store_agency:
            store_name = store_agency.ebf_agency_name
            address = f'现场自提订单【{store_name}】'
            serial_no = pay.sdef_order_room_id  # room_id redefined as store's daily serial no
            if serial_no:
                address = f'现场自提订单【{store_name} {serial_no}】'
            pass
        else:
            logger.error(f'门店 store_id={store_id} 记录不存在！')
            session.close()
            return

        try:
            # 通知门店
            url = f'https://{DOMAIN}/admin/partner'
            agency_id = store_id
            user_agency = (
                session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
            )
            agency_open_id = user_agency.ebf_ua_bind_user_id if user_agency else None
            if agency_open_id:
                logger.info(
                    f'send_store_order_notice: 开始通知 open_id={agency_open_id} order_id={order_id}'
                )
                tasks.send_new_order_notice.delay(
                    agency_open_id, first, order_id, time, goods, address, remark, url
                )
            else:
                logger.error(
                    f'send_store_order_notice: 合伙人没绑定微信！agency_id={agency_id} order_id={order_id}'
                )

            # 通知店员
            agencies = (
                session.query(Agency)
                .filter_by(
                    ebf_agency_parent_id=store_id, ebf_agency_type=AgencyType.CLERK
                )
                .all()
            )
            if agencies:
                for a in agencies:
                    agency_id = a.ebf_agency_id
                    user_agency = (
                        session.query(UserAgency)
                        .filter_by(ebf_agency_id=agency_id)
                        .first()
                    )
                    agency_open_id = (
                        user_agency.ebf_ua_bind_user_id if user_agency else None
                    )
                    # 异步发送模版消息
                    if agency_open_id:
                        logger.info(
                            f'send_store_order_notice: 开始通知 open_id={agency_open_id} order_id={order_id}'
                        )
                        tasks.send_new_order_notice.delay(
                            agency_open_id,
                            first,
                            order_id,
                            time,
                            goods,
                            address,
                            remark,
                            url,
                        )
                    else:
                        logger.error(
                            f'send_store_order_notice: 合伙人没绑定微信！agency_id={agency_id} order_id={order_id}'
                        )
            else:
                logger.error(
                    f'send_store_order_notice: 无门店合伙人记录！agency_id={store_id} order_id={order_id}'
                )
        except Exception as e:
            logger.exception(e)
            logger.error(f'send_store_order_notice: failed order_id: {order_id}')
        else:
            logger.info(f'send_store_order_notice: success order_id: {order_id}')
    else:
        # 线上订单通知 - 通知直属合伙人
        try:
            agency_uid = pay.sdef_order_agency_uid
            agency = AgencyHelper.get_agency(agency_uid)
            agency_id = agency.ebf_agency_id
            agency_openid = AgencyHelper.get_agency_openid(agency_id)
            order_type = pay.sdef_order_type
            total_fee = (
                pay.sdef_order_fee + pay.sdef_order_balance_fee + pay.sdef_order_coupon_fee
            )
            fee = '%.2f' % total_fee
            first = '您朋友下了一个订单！'
            remark = '我们衷心感谢您和您的朋友！'
            url = f'https://{DOMAIN}/order/{order_id}'
            tasks.send_order_pay_success_notice.delay(
                agency_openid, order_id, fee, store_id, order_type, first, remark, url
            )
        except Exception as e:
            logger.exception(e)
            logger.error(f'给合伙人发送订单通知失败：order_id={order_id} agency_id={agency_id}')

    if pay.sdef_order_type != OrderType.MEMBER:
        # 通知用户
        oid = pay.sdef_order_device_id
        order_type = pay.sdef_order_type
        total_fee = (
            pay.sdef_order_fee + pay.sdef_order_balance_fee + pay.sdef_order_coupon_fee
        )
        fee = '%.2f' % total_fee
        first = None
        remark = None
        url = None
        if pay.sdef_order_remarks == '合伙人注册499元赠品订单':
            first = '欢迎您注册成为莱支好酒合伙人！'
            remark = '这是您注册支付499元后系统自动生成的赠品订单。欢迎您继续邀请新合伙人。'
        # 开店酬宾活动
        if promotion.SHOP_OPENING_PROMO_GOODS_ID in pay.sdef_order_goods:
            first = '欢迎您参与莱支好酒开店酬宾活动！'
            remark = (
                f'恭喜您此单被抽中获得2个100元现金红包：点击链接分享活动海报，邀成一人奖100，两人奖200元秒到账秒提现，实际到手价99元/箱。'
            )
            url = f'https://{DOMAIN}/wx/promotion'
        tasks.send_order_pay_success_notice.delay(
            oid, order_id, fee, store_id, order_type, first, remark, url
        )

    # 通知公司同事
    url = f'https://{DOMAIN}/order/{order_id}'
    if pay.sdef_order_type == OrderType.FREE_CARD and pay.sdef_order_fee < Decimal(200):
        paid_fee = '%.2f' % pay.sdef_order_fee
        remark = f'门店体验卡买单实付金额低于200元报警！！！【实付金额：{paid_fee}元】'

    logger.info(
        f'send_store_order_notice: 开始通知 open_id={config.COMMON_NOTICE_RECEIVER} order_id={order_id}'
    )
    tasks.send_new_order_notice.delay(
        config.COMMON_NOTICE_RECEIVER,
        first,
        order_id,
        time,
        goods,
        address,
        remark,
        url,
    )


def expedite_order_notice(order_id):
    """
    新订单通知平台/供应商发货

    expedite_order_notice(15573004468645913)

    :param: order_id
    :return:
    """

    class GoodsOrder(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class User(object):
        pass

    class Address(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'sdet_address', 'model': Address},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'expedite_order_notice: 订单不存在 order_id={order_id}')
        session.close()
        return

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.error(f'expedite_order_notice: 订单未支付 order_id={order_id}')
        session.close()
        return

    if pay.sdef_order_status != OrderStatus.WAIT_EXPRESS:
        logger.info(f'expedite_order_notice: 非待发货订单 order_id={order_id}')
        session.close()
        return

    # 通知内容
    first = '你有订单未发货, 请及时发货！'

    goods = ''
    goods_info = []
    if pay.sdef_order_goods:
        goods_info = json.loads(pay.sdef_order_goods)  # 特殊订单没有商品信息

    for g in goods_info:
        goods_name = g['goods_name']
        count = Decimal(g['count'])
        goods += f'{goods_name} x {count} \n'

    time = (
        (pay.sdef_order_pay_time).strftime('%Y-%m-%d %H:%M:%S')
        if pay.sdef_order_pay_time
        else ''
    )
    url = f'https://{DOMAIN}/admin/partner'
    remark = f'请及时发货并更新物流信息'

    address = '线上商城'

    supplier_id = pay.sdef_order_supplier_id
    order_status = pay.sdef_order_status
    if supplier_id and order_status == OrderStatus.WAIT_PICKUP:
        try:
            # 通知供应商发货
            agency_id = supplier_id
            user_agency = (
                session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
            )
            agency_open_id = user_agency.ebf_ua_bind_user_id if user_agency else None
            if agency_open_id:
                logger.info(
                    f'expedite_order_notice: 开始通知供应商发货 open_id={agency_open_id} agency_id={agency_id} order_id={order_id}'
                )
                tasks.send_new_order_notice.delay(
                    agency_open_id, first, order_id, time, goods, address, remark, url
                )
            else:
                logger.error(
                    f'expedite_order_notice: 供应商没绑定微信！agency_id={agency_id} order_id={order_id}'
                )

            # 通知供应商职员
            agencies = (
                session.query(Agency)
                .filter_by(
                    ebf_agency_parent_id=supplier_id, ebf_agency_type=AgencyType.CLERK
                )
                .all()
            )
            if agencies:
                for a in agencies:
                    agency_id = a.ebf_agency_id
                    user_agency = (
                        session.query(UserAgency)
                        .filter_by(ebf_agency_id=agency_id)
                        .first()
                    )
                    agency_open_id = (
                        user_agency.ebf_ua_bind_user_id if user_agency else None
                    )
                    # 异步发送模版消息
                    if agency_open_id:
                        logger.info(
                            f'expedite_order_notice: 开始通知 open_id={agency_open_id} order_id={order_id}'
                        )
                        tasks.send_new_order_notice.delay(
                            agency_open_id,
                            first,
                            order_id,
                            time,
                            goods,
                            address,
                            remark,
                            url,
                        )
                    else:
                        logger.error(
                            f'expedite_order_notice: 供应商职员没绑定微信！agency_id={agency_id} order_id={order_id}'
                        )
            else:
                logger.error(
                    f'expedite_order_notice: 无供应商职员记录！agency_id={supplier_id} order_id={order_id}'
                )
        except Exception as e:
            logger.exception(e)
            logger.error(f'expedite_order_notice: failed order_id: {order_id}')
        else:
            logger.info(f'expedite_order_notice: success order_id: {order_id}')
    else:
        # 通知平台发货
        address_id = pay.sdef_order_address_id
        a = session.query(Address).filter_by(sdef_address_id=address_id).first()
        if a:
            address = f'{a.sdef_address_province}{a.sdef_address_city}{a.sdef_address_county}{a.sdef_address_detail} {a.sdef_address_name} {a.sdef_address_phone}'

        logger.info(
            f'expedite_order_notice: 开始通知平台发货 open_id={config.COMMON_NOTICE_RECEIVER} order_id={order_id}'
        )
        tasks.send_new_order_notice.delay(
            config.COMMON_NOTICE_RECEIVER,
            first,
            order_id,
            time,
            goods,
            address,
            remark,
            url,
        )


def send_order_pickup_notice(order_id):
    """
    待提货订单通知供应商发货

    send_order_pickup_notice(15573004468645913)

    :param: order_id
    :return:
    """

    class GoodsOrder(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class User(object):
        pass

    class Address(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'sdet_address', 'model': Address},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'send_order_pickup_notice: 订单不存在 order_id={order_id}')
        session.close()
        return

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.error(f'send_order_pickup_notice: 订单未支付 order_id={order_id}')
        session.close()
        return

    if pay.sdef_order_status != OrderStatus.WAIT_PICKUP:
        logger.info(f'send_order_pickup_notice: 非待提货货订单 order_id={order_id}')
        session.close()
        return

    # 通知内容
    first = '你有一个待提货订单, 请及时按要求发货并在后台确认发货。'

    goods = ''
    goods_info = json.loads(pay.sdef_order_goods)

    for g in goods_info:
        goods_name = g['goods_name']
        count = Decimal(g['count'])
        goods += f'{goods_name} x {count} \n'

    time = (
        (pay.sdef_order_pay_time).strftime('%Y-%m-%d %H:%M:%S')
        if pay.sdef_order_pay_time
        else ''
    )
    url = f'https://{DOMAIN}/static/admin/index.html#/indexSr'

    remark = ''
    for express_info in json.loads(pay.sdef_order_express_no):
        express_name = express_info['express_name']
        express_number = express_info['express_number']
        express_remarks = express_info['express_remarks']
        remark += f'物流公司: {express_name} 单号: {express_number} 备注: {express_remarks}\n'

    address = '线上商城'

    supplier_id = pay.sdef_order_supplier_id
    if supplier_id:
        try:
            # 通知供应商发货
            agency_id = supplier_id
            user_agency = (
                session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
            )
            agency_open_id = user_agency.ebf_ua_bind_user_id if user_agency else None
            if agency_open_id:
                logger.info(
                    f'send_order_pickup_notice 开始通知供应商发货 open_id={agency_open_id} agency_id={agency_id} order_id={order_id}'
                )
                tasks.send_new_order_notice.delay(
                    agency_open_id, first, order_id, time, goods, address, remark, url
                )
            else:
                logger.error(
                    f'send_order_pickup_notice: 供应商没绑定微信！agency_id={agency_id} order_id={order_id}'
                )

            # 通知供应商职员
            agencies = (
                session.query(Agency)
                .filter_by(
                    ebf_agency_parent_id=supplier_id, ebf_agency_type=AgencyType.CLERK
                )
                .all()
            )
            if agencies:
                for a in agencies:
                    agency_id = a.ebf_agency_id
                    user_agency = (
                        session.query(UserAgency)
                        .filter_by(ebf_agency_id=agency_id)
                        .first()
                    )
                    agency_open_id = (
                        user_agency.ebf_ua_bind_user_id if user_agency else None
                    )
                    # 异步发送模版消息
                    if agency_open_id:
                        logger.info(
                            f'send_order_pickup_notice: 开始通知 open_id={agency_open_id} order_id={order_id}'
                        )
                        tasks.send_new_order_notice.delay(
                            agency_open_id,
                            first,
                            order_id,
                            time,
                            goods,
                            address,
                            remark,
                            url,
                        )
                    else:
                        logger.error(
                            f'send_order_pickup_notice: 供应商职员没绑定微信！agency_id={agency_id} order_id={order_id}'
                        )
            else:
                logger.error(
                    f'send_order_pickup_notice: 无供应商职员记录！agency_id={supplier_id} order_id={order_id}'
                )
        except Exception as e:
            logger.exception(e)
            logger.error(f'send_order_pickup_notice: failed order_id: {order_id}')
        else:
            logger.info(f'send_order_pickup_notice: success order_id: {order_id}')
    else:
        # 通知平台发货
        address_id = pay.sdef_order_address_id
        a = session.query(Address).filter_by(sdef_address_id=address_id).first()
        if a:
            address = f'{a.sdef_address_province}{a.sdef_address_city}{a.sdef_address_county}{a.sdef_address_detail} {a.sdef_address_name} {a.sdef_address_phone}'
        logger.info(
            f'send_order_pickup_notice: 开始通知平台发货 open_id={config.COMMON_NOTICE_RECEIVER} order_id={order_id}'
        )
        tasks.send_new_order_notice.delay(
            config.COMMON_NOTICE_RECEIVER,
            first,
            order_id,
            time,
            goods,
            address,
            remark,
            url,
        )


def is_promotion_order(order_id):
    """
    判断是否线下订单促销订单
    (新用户首瓶促销I款支付139元，奖励店员30元)

    is_promotion_order(15556579325056302)
    False

    :param: order_id:
    :return:
    """

    # 设置促销商品
    PROMOTION_GOODS_ID = promotion.PROMOTION_GOODS_ID

    class GoodsOrder:
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return False
    if PROMOTION_GOODS_ID not in pay.sdef_order_goods:
        logger.info(f'order_id={order_id} has no promotion goods')
        session.close()
        return False

    # 判断订单是否用户首个促销商品的线下订单
    user_id = pay.sdef_order_device_id
    order_count = (
        session.query(GoodsOrder)
        .filter_by(
            sdef_order_device_id=user_id,
            sdef_order_pay_status=PayStatus.SUCCESS,
        )
        .count()
    )
    session.close()
    if order_count > 1:
        # 非首次购买
        logger.info(f'order_id={order_id} is not first buy')
        session.close()
        return False

    # 这是用户的首个订单，包含促销商品
    logger.info(f'order_id={order_id} is promotion order')
    session.close()
    return True


def reward_money(order_id):
    """
    奖励购买私人酒庄用户及推荐人收益或余额

    :param order_id:
    :return:
    """
    logger.info(f'奖励购买私人酒庄用户及推荐人收益或余额: order_id={order_id}')
    goods_id = '558922117868242'  # 设置私人酒庄商品
    money_to_user = 4988  # 奖励用户自己4988元余额/每份私人酒庄
    money_to_store = 588  # 奖励用户上级或商家588元收益/每份私人酒庄
    money_to_store_career = 300  # 奖励商家或用户所属的经销商300元收益/每份私人酒庄
    money_to_store_career_parent = 100  # 奖励经销商上级100元收益/每份私人酒庄
    type = 2  # 收益类型

    class GoodsOrder:
        pass

    class Benefit(object):
        pass

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class AccountMoney(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_account_money', 'model': AccountMoney},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.info(f'订单不存在 {order_id}')
        session.close()
        return False

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return False

    if goods_id not in pay.sdef_order_goods:
        logger.info(f'order_id={order_id} has no winery goods')
        session.close()
        return False

    cart_goods = json.loads(pay.sdef_order_goods)
    winery = list(filter(lambda g: g['id'] == goods_id, cart_goods))
    count = int(winery[0]['count'])  # 统计私人酒庄商品品份数
    money_to_user *= count
    money_to_store *= count
    money_to_store_career *= count
    money_to_store_career_parent *= count
    user_id = pay.sdef_order_device_id
    user = session.query(User).filter_by(ebf_user_id=user_id).first()
    if not user:
        logger.error(f'user表无记录: order_id={order_id}, open_id={user_id}')
        session.close()
        return False

    name = user.ebf_user_nickname
    store_id = pay.sdef_order_store_id
    beneficiary_list = []
    ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=user_id).first()
    try:
        if store_id > 0:
            # 线下门店
            store = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            store_ua = (
                session.query(UserAgency).filter_by(ebf_agency_id=store_id).first()
            )
            store_oid = store_ua.ebf_ua_bind_user_id
            store_uid = store.ebf_agency_uid
            beneficiary_list.append([store_oid, store_uid])
            parent_uid = store_uid
        else:
            # 线上商城
            if ua:
                # 用户本身是合伙人身份
                agency_id = ua.ebf_agency_id
                agency = (
                    session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
                )
                parent_id = agency.ebf_agency_parent_id
                parent_agency = (
                    session.query(Agency).filter_by(ebf_agency_id=parent_id).first()
                )
                parent_uid = parent_agency.ebf_agency_uid
            else:
                # 用户非合伙人
                parent_uid = pay.sdef_order_agency_uid
                parent_agency = (
                    session.query(Agency).filter_by(ebf_agency_uid=parent_uid).first()
                )
                parent_id = parent_agency.ebf_agency_id
            parent_ua = (
                session.query(UserAgency).filter_by(ebf_agency_id=parent_id).first()
            )
            parent_oid = parent_ua.ebf_ua_bind_user_id
            beneficiary_list.append([parent_oid, parent_uid])

        career_agency = AgencyHelper.get_career_agency(parent_uid)
        if career_agency:
            career_uid = career_agency.ebf_agency_uid
            career_id = career_agency.ebf_agency_id
            career_ua = (
                session.query(UserAgency).filter_by(ebf_agency_id=career_id).first()
            )
            career_oid = career_ua.ebf_ua_bind_user_id if career_ua else None
            beneficiary_list.append([career_oid, career_uid])
            career_parent_id = career_agency.ebf_agency_parent_id
            career_parent_agency = (
                session.query(Agency).filter_by(ebf_agency_id=career_parent_id).first()
            )
            career_parent_uid = (
                career_parent_agency.ebf_agency_uid if career_parent_agency else None
            )
            if career_parent_uid:
                career_parent_ua = (
                    session.query(UserAgency)
                    .filter_by(ebf_agency_id=career_parent_id)
                    .first()
                )
                career_parent_oid = career_parent_ua.ebf_ua_bind_user_id
                beneficiary_list.append(
                    [career_parent_oid, career_parent_uid, money_to_store_career_parent]
                )
        logger.info(
            f'order_id={order_id}, open_id={user_id}, beneficiary_list={beneficiary_list}'
        )

        # 给私人酒庄购买人充值余额
        describe = '购买私人酒庄奖励'
        first = f'购买私人酒庄成功，奖励{money_to_user}元余额已到账，余额可在线上商城或线下门店购酒使用！'
        result = BalanceHandler.add_manual_money(
            user_id, money_to_user, operator=order_id, ip='', pay_content=describe
        )
        if result:
            logger.info(f'winery奖励充值成功： order_id={order_id}, user_id={user_id}')
            am = session.query(AccountMoney).filter_by(ebf_am_user_id=user_id).first()
            if not am:
                am_money = money_to_user
            else:
                am_money = (am.ebf_am_money + Decimal(money_to_user)).quantize(
                    Decimal('1.00')
                )
            tasks.send_balance_reward_notice.delay(
                user_id, money_to_user, order_id, am_money, first
            )
        else:
            logger.error(f'winery奖励充值失败： order_id={order_id}, user_id={user_id}')

        # 给用户直属上级及经销商创建收益记录
        nums = len(beneficiary_list)
        if nums >= 2:
            if beneficiary_list[0][1] == beneficiary_list[1][1]:
                money = money_to_store + money_to_store_career
                beneficiary_list.pop(1)
                beneficiary_list[0].append(money)
            else:
                beneficiary_list[0].append(money_to_store)
                beneficiary_list[1].append(money_to_store_career)
        else:
            beneficiary_list[0].append(money_to_store)
        for i in beneficiary_list:
            if i[1] != config.DEFAULT_AGENCY_UID:
                reward = i[2]
                order_fee = (
                    pay.sdef_order_fee
                    + pay.sdef_order_balance_fee
                    + pay.sdef_order_coupon_fee
                )
                rate = round(float(reward / order_fee), 2)
                now = datetime.datetime.now()
                benefit = Benefit()
                benefit.order_id = order_id
                benefit.factory_uid = config.FACTORY_UID
                benefit.agency_uid = i[1]
                benefit.type = type
                benefit.fee = Decimal(reward)
                benefit.order_fee = order_fee
                benefit.rate = rate
                benefit.status = 1
                benefit.is_valid = 1
                benefit.is_finish = 1
                benefit.remarks = '名下用户购买私人酒庄奖励'
                benefit.update_time = now
                benefit.create_time = now
                session.add(benefit)
                first = '恭喜您名下的 “' + name + '” 购买私人酒庄成功！'
                key = '名下用户购买私人酒庄奖励'
                tasks.send_benefit_reward_notice.delay(
                    first, key, i[0], reward, order_id
                )
                logger.info(
                    f'winery创建收益记录成功: order_id={order_id}, reward={reward}, touser={i[0]}'
                )
        user.ebf_user_level = 1  # 购买私人酒庄的用户升级为会员 用户级别：0=普通用户 1=1级会员
        session.commit()
        session.close()
        return True
    except Exception as e:
        logger.error(f'购买私人酒庄用户及直属上级和经销商奖励失败: order_id={order_id}, error={e}')
        session.rollback()
        session.close()
        return False


def reward_money2(order_id):
    """
    奖励购买私人酒庄用户及推荐人收益或余额

    :param order_id:
    :return:
    """
    logger.info(f'reward_money2: order_id={order_id}')
    goods_id1 = '561774248859721'  # 设置私人酒庄商品
    goods_id2 = '562225951936393'  # 设置经销商加盟商品
    money_to_career = 100  # 奖励事业合伙人100元收益/每份私人酒庄
    type = 2  # 收益类型

    class GoodsOrder:
        pass

    class Benefit(object):
        pass

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class AccountMoney(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_account_money', 'model': AccountMoney},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.info(f'订单不存在 {order_id}')
        session.close()
        return False

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return False

    if goods_id1 not in pay.sdef_order_goods and goods_id2 not in pay.sdef_order_goods:
        logger.info(f'order_id={order_id} has no winery goods')
        session.close()
        return False

    if goods_id1 in pay.sdef_order_goods:
        money_to_user = 3999  # 奖励用户自己3999元余额/每份私人酒庄
        money_to_recommender = 399  # 奖励推荐人399元余额或收益/每份私人酒庄
        goods_id = goods_id1

    if goods_id2 in pay.sdef_order_goods:
        money_to_user = 36000  # 奖励用户自己36000元余额/每份经销商加盟商品
        money_to_recommender = 1000  # 奖励推荐人1000元收益/每份经销商加盟商品
        goods_id = goods_id2

    cart_goods = json.loads(pay.sdef_order_goods)
    winery = list(filter(lambda g: g['id'] == goods_id, cart_goods))
    count = int(winery[0]['count'])
    money_to_user *= count
    money_to_recommender *= count
    money_to_career *= count
    user_id = pay.sdef_order_device_id
    user = session.query(User).filter_by(ebf_user_id=user_id).first()
    logger.info(f'count={count}, goods_id={goods_id}, order_id={order_id}')
    if not user:
        logger.error(f'user表无记录: order_id={order_id}, open_id={user_id}')
        session.close()
        return False

    ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=user_id).first()
    if ua:
        agency = session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
        if agency and agency.ebf_agency_type in [0, 5] and goods_id == goods_id1:
            agency.ebf_agency_type = 1
        if agency and agency.ebf_agency_type in [0, 1, 5] and goods_id == goods_id2:
            agency.ebf_agency_type = 2
    else:
        logger.info(f'非合伙人身份:order_id={order_id}, goods_id={goods_id}, oid={user_id}')

    name = user.ebf_user_nickname
    recommend_user_id = user.ebf_user_recommend_user
    recommend_ua = (
        session.query(UserAgency)
        .filter_by(ebf_ua_bind_user_id=recommend_user_id)
        .first()
    )
    recommend_agency = None
    agency_uid = user.ebf_user_agency_uid
    logger.info(
        f'order_id={order_id}, open_id={user_id}, recommend_user={recommend_user_id}, uid={agency_uid}'
    )
    balance_list = [[user_id, money_to_user]]
    benefit_list = []
    if recommend_ua:
        recommend_agency_id = recommend_ua.ebf_agency_id
        recommend_agency = (
            session.query(Agency).filter_by(ebf_agency_id=recommend_agency_id).first()
        )

    if recommend_agency:
        benefit_list.append(
            [recommend_user_id, recommend_agency.ebf_agency_uid, money_to_recommender]
        )
    else:
        if recommend_user_id and recommend_user_id != user_id and goods_id == goods_id1:
            balance_list.append([recommend_user_id, money_to_recommender])

    if agency_uid and goods_id == goods_id1:
        career_agency = AgencyHelper.get_career_agency(agency_uid)
        if career_agency:
            career_uid = career_agency.ebf_agency_uid
            career_id = career_agency.ebf_agency_id
            career_ua = (
                session.query(UserAgency).filter_by(ebf_agency_id=career_id).first()
            )
            career_oid = career_ua.ebf_ua_bind_user_id if career_ua else None
            benefit_list.append([career_oid, career_uid, money_to_career])
    logger.info(
        f'order_id={order_id}, open_id={user_id}, benefit_list={benefit_list}, balance_list={balance_list}'
    )
    nums = len(benefit_list)
    if nums == 2:
        if benefit_list[0][1] == benefit_list[1][1]:
            money = money_to_recommender + money_to_career
            benefit_list.pop(1)
            benefit_list[0][2] = money

    try:
        if goods_id == goods_id1:
            key = '私人酒庄推荐奖励'
            first = f'恭喜您邀请的 “{name}” 购买私人酒庄成功'
            describe = '购买私人酒庄充值等额余额'
            content = '恭喜您购买私人酒庄成功'
        else:
            key = '经销商加盟推荐奖励'
            first = f'恭喜您邀请的 “{name}” 加盟经销商成功'
            describe = '加盟经销商充值余额'
            content = '恭喜您加盟经销商成功'
        for bf in benefit_list:
            if bf[1] != config.DEFAULT_AGENCY_UID:
                reward = bf[2]
                order_fee = (
                    pay.sdef_order_fee
                    + pay.sdef_order_balance_fee
                    + pay.sdef_order_coupon_fee
                )
                rate = round(float(reward / order_fee), 2)
                now = datetime.datetime.now()
                benefit = Benefit()
                benefit.order_id = order_id
                benefit.factory_uid = config.FACTORY_UID
                benefit.agency_uid = bf[1]
                benefit.type = type
                benefit.fee = Decimal(reward)
                benefit.order_fee = order_fee
                benefit.rate = rate
                benefit.status = 1
                benefit.is_valid = 1
                benefit.is_finish = 1
                benefit.remarks = key
                benefit.update_time = now
                benefit.create_time = now
                session.add(benefit)
                tasks.send_benefit_reward_notice.delay(
                    first, key, bf[0], reward, order_id
                )
                logger.info(
                    f'winery创建收益记录成功: order_id={order_id}, reward={reward}, touser={bf[0]}'
                )

        for bc in balance_list:
            touser = bc[0]
            money = bc[1]
            if touser == user_id:
                describe = describe
                first = f'{content}，充值{money}元余额已到账，余额可在线上商城或线下门店购酒使用！'
            else:
                describe = '私人酒庄推荐奖励'
                first = f'恭喜您邀请的 “{name}” 购买私人酒庄成功！奖励{money}元余额已到账，余额可在线上商城或线下门店购酒使用！'
            result = BalanceHandler.add_manual_money(
                touser, money, operator=order_id, ip='', pay_content=describe
            )
            if result:
                logger.info(
                    f'奖励充值成功： order_id={order_id}, user_id={touser}, money={money}'
                )
                am = (
                    session.query(AccountMoney).filter_by(ebf_am_user_id=touser).first()
                )
                if not am:
                    am_money = money
                else:
                    am_money = (am.ebf_am_money + Decimal(money)).quantize(
                        Decimal('1.00')
                    )
                tasks.send_balance_reward_notice.delay(
                    touser, money, order_id, am_money, first
                )
            else:
                logger.error(
                    f'奖励充值失败： order_id={order_id}, user_id={touser}, money={money}, goods_id={goods_id}'
                )
        session.commit()
        session.close()
        return True
    except Exception as e:
        logger.error(f'奖励失败: order_id={order_id}, error={e}, goods_id={goods_id}')
        session.rollback()
        session.close()
        return False


def return_to_giver_benefit(order_id):
    """
    返还送礼人5元卡费

    :param order_id:
    :return:
    """
    logger.info(f'return_to_giver_benefit: order_id={order_id}')
    money = 5
    type = 2  # 收益类型

    class GoodsOrder:
        pass

    class Benefit(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.info(f'订单不存在 {order_id}')
        session.close()
        return False

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return False

    if pay.sdef_order_type != OrderType.GIFT_CARD:
        logger.info(f'非礼品卡订单 {order_id}')
        session.close()
        return False

    oid = pay.sdef_order_device_id
    card_id = pay.sdef_order_courier_phone

    gift_id = int(card_id)
    if gift_id < 1000000000:
        # 送礼订单
        logger.info(f'送礼订单不返还5元：非礼品卡订单 {order_id}')
        return False

    try:
        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=oid).first()
        agency_id = ua.ebf_agency_id
        agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
        uid = agency.ebf_agency_uid
        first = f'编号为{card_id}的礼品卡激活成功，卡费已返还到您的账号，可以随时提现到微信钱包！'
        key = '礼品卡卡费返还'
        order_fee = (
            pay.sdef_order_fee + pay.sdef_order_balance_fee + pay.sdef_order_coupon_fee
        )
        rate = round(float(money / order_fee), 2)
        now = datetime.datetime.now()
        benefit = Benefit()
        benefit.order_id = order_id
        benefit.factory_uid = config.FACTORY_UID
        benefit.agency_uid = uid
        benefit.type = type
        benefit.fee = Decimal(money)
        benefit.order_fee = order_fee
        benefit.rate = rate
        benefit.status = 1
        benefit.is_valid = 1
        benefit.is_finish = 1
        benefit.remarks = key
        benefit.update_time = now
        benefit.create_time = now
        session.add(benefit)
        tasks.send_benefit_reward_notice.delay(first, key, oid, money, order_id)
        logger.info(f'返还卡费成功: order_id={order_id}, money={money}, touser={oid}')
        session.commit()
        session.close()
        return True
    except Exception as e:
        logger.error(f'返还失败: order_id={order_id}, error={e}, oid={oid}')
        session.close()
        return False


def update_complete_benefit(order_id):
    """修改礼品卡/体验卡订单收益为实时完成"""

    class GoodsOrder:
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
        ]
    )

    logger.info(f'update_complete_benefit: order_id={order_id}')
    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.info(f'订单不存在 {order_id}')
        session.close()
        return False

    # 体验卡订单、礼品卡订单实时结算
    if pay.sdef_order_type in [OrderType.GIFT_CARD, OrderType.FREE_CARD]:
        BenefitHelper.create_complete_order(order_id)

    session.close()
    return True


def get_red_packet(order_id):
    """领取红包"""

    class GoodsOrder:
        pass

    class Benefit(object):
        pass

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class AccountMoney(object):
        pass

    class Pay(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_account_money', 'model': AccountMoney},
            {'db_table': 'ebt_pay', 'model': Pay},
        ]
    )

    logger.info(f'get_red_packet: order_id={order_id}')
    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.info(f'订单不存在 {order_id}')
        session.close()
        return False

    if pay.sdef_order_type != OrderType.FREE_CARD:
        session.close()
        return False

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return False

    if pay.sdef_order_fee < Decimal('1.00'):
        logger.info(f'订单金额小于一元 {order_id}')
        session.close()
        return False

    # 红包金额为实付金额的(1%-5%)
    # rate = Decimal(str(random.randint(1, 5) / 100)) # 红包金额所占实付款比例(1%-5%)
    # fee = pay.sdef_order_fee
    # money = (rate * fee).quantize(Decimal('0.00')) # 红包随机金额

    # 红包金额改为20%订单金额的1%～10%
    fee = pay.sdef_order_fee
    b = fee * Decimal('0.20')
    if b > Decimal('99.00'):
        b = Decimal('99.00')
    money = Decimal(str((random.random() * 9 + 1) / 100)) * b
    money = money.quantize(Decimal('1.00'))
    rate = float(round(money / fee, 2))
    user_id = pay.sdef_order_device_id
    ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=user_id).first()
    now = datetime.datetime.now()
    msg = f'get_red_packet红包领取成功: order_id={order_id} open_id={user_id} money={money}'
    b_type = 2
    if ua:
        agency = session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
        if not agency:
            logger.error(f'agency表无记录 order_id={order_id} open_id={user_id}')
            session.close()
            return False
        key = '体验卡买单随机红包'
        first = '恭喜您获得随机红包一个，可以提现到微信钱包或转入商城余额用来购酒！'
        uid = agency.ebf_agency_uid
        filters = dict(order_id=order_id, agency_uid=uid, type=b_type, remarks=key)
        old_benefit = session.query(Benefit).filter_by(**filters).first()
        if old_benefit:
            session.close()
            return old_benefit.fee
        benefit = Benefit()
        benefit.order_id = order_id
        benefit.factory_uid = config.FACTORY_UID
        benefit.agency_uid = uid
        benefit.type = b_type
        benefit.fee = money
        benefit.order_fee = fee
        benefit.rate = rate
        benefit.status = 1
        benefit.is_valid = 1
        benefit.is_finish = 1
        benefit.remarks = key
        benefit.update_time = now
        benefit.create_time = now
        session.add(benefit)
        session.commit()
        tasks.send_benefit_reward_notice.delay(first, key, user_id, money, order_id)
        logger.info(msg)
    else:
        describe = '体验卡买单随机红包'
        first = '恭喜您获得随机红包一个，已转入商城余额，可以在线上商城或线下门店用来购酒！'
        filters = dict(ebf_user_id=user_id, ebf_pay_remarks=f'充值人员：{order_id}')
        old_balance = session.query(Pay).filter_by(**filters).first()
        if old_balance:
            session.close()
            return old_balance.ebf_pay_fee
        result = BalanceHandler.add_manual_money(
            user_id, money, operator=order_id, ip='', pay_content=describe
        )
        if result:
            logger.info(msg)
            am = session.query(AccountMoney).filter_by(ebf_am_user_id=user_id).first()
            if not am:
                am_money = money
            else:
                am_money = (am.ebf_am_money + money).quantize(Decimal('0.00'))
            tasks.send_balance_reward_notice.delay(
                user_id, money, order_id, am_money, first
            )
        else:
            logger.error(
                f'get_red_packet红包领取失败： order_id={order_id}, user_id={user_id}, money={money}'
            )
            session.close()
            return False
    session.close()
    return money


def reward_user_register(open_id):
    """
    给用户所属合伙人0.2元收益，每个用户直属合伙人名下每天累计收益200元封顶（1000个新用户）

    reward_user_register('o7qyl0g-QB_gIV16O98DMUYatiZE')

    :param open_id: 新用户的open_id
    :return:
    """
    logger.info(f'新用户扫码: 开始计算奖励 open_id={open_id}')

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class Benefit(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
        ]
    )

    user = session.query(User).filter_by(ebf_user_id=open_id).first()

    if not user:
        logger.error('新用户扫码: 用户不存在 open_id={open_id}')
        session.close()
        return

    agency_uid = user.ebf_user_agency_uid
    agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
    agency_id = agency.ebf_agency_id

    if not agency:
        logger.error('新用户扫码: 合伙人不存在 open_id={open_id}')
        session.close()
        return

    # 判断是否发卡商户 (发卡商户类型5.3)
    # if agency.ebf_agency_type != AgencyType.NEW_PARTNER or agency.ebf_agency_sub_type != 3:
    #     logger.info(f'新用户扫码: 非发卡商户用户 open_id={open_id}')
    #     session.close()
    #     return

    user_count = session.query(User).filter_by(ebf_user_agency_uid=agency_uid).count()
    count_today = (
        session.query(User)
        .filter(
            and_(
                User.ebf_user_agency_uid == agency_uid,
                cast(User.ebf_user_create_date, Date) == datetime.date.today(),
            )
        )
        .count()
    )

    # 合伙人每天扫码奖励1000个封顶
    if count_today > 1000:
        logger.info(f'新用户扫码: 今天第{count_today}个 open_id={open_id}')
        session.close()
        return

    order_id = generator_trade_no()  # 虚拟订单号

    # 给发卡商直接刺激
    benefit = Decimal('0.20')
    rate = float(0)
    order_fee = Decimal('0.00')
    remarks = '新用户扫码奖励'

    # 创建实时结算收益
    BenefitHelper.create_completed_benefit_record(
        BenefitType.PARENT, order_id, agency_uid, benefit, order_fee, rate, remarks
    )

    # 发送模版消息
    user_agency = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
    if user_agency:
        reward_open_id = user_agency.ebf_ua_bind_user_id
        if reward_open_id:
            first = '恭喜您名下有新用户扫码成功'
            key = '新用户扫码奖励'
            tasks.send_benefit_reward_notice.delay(
                first, key, reward_open_id, benefit, order_id
            )

    logger.info(
        f'{remarks} 第{user_count}个扫码成功 open_id={open_id} reward_agency_id={agency_id}'
    )


def reward_agency_user_register(agency_uid):
    logger.info(f'新用户扫码: 开始发卡人奖励 agency_uid={agency_uid}')
    benefit = Decimal('2.00')
    rate = float(0)
    order_id = generator_trade_no()  # 虚拟订单号
    order_fee = Decimal('0.00')
    remarks = '发卡人奖励'

    # 创建实时结算收益
    BenefitHelper.create_completed_benefit_record(
        BenefitType.PARENT, order_id, agency_uid, benefit, order_fee, rate, remarks
    )

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class Benefit(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
        ]
    )

    agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
    agency_id = agency.ebf_agency_id
    # 给发卡人发送微信消息
    user_agency = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
    agency_open_id = user_agency.ebf_ua_bind_user_id
    first = '您有一个新订单参与分润，收益如下：'
    now = (
        datetime.datetime.now()
        .strftime('%Y{y}%m{m}%d{d} %H:%M:%S')
        .format(y='年', m='月', d='日')
    )
    tasks.send_order_benefit_notice.delay(
        first, order_id, order_fee, benefit, agency_open_id, now
    )
    logger.info(f'新用户扫码: 完成发卡人奖励 agency_uid={agency_uid}')


def auto_cash_apply(
        agency_uid, amount, cash_method=CashMethod.WECHAT, ip='118.126.94.161'
):
    """
    自动提现

    :param agency_uid: 合伙人UID
    :param amount: 提现金额
    :param cash_method: 提现方式，默认微信提现
    :param ip: 提现IP，默认系统IP
    :return: 是否成功
    """

    class Agency(object):
        pass

    class AgencyIncome(object):
        pass

    class UserAgency(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'slbt_agency_income_setup', 'model': AgencyIncome},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
        ]
    )

    agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
    if not (agency_uid and agency):
        logger.error(f'自动提现失败: 没有合伙人记录 agency_uid={agency_uid}')
        session.close()
        return False

    agency_id = agency.ebf_agency_id
    user_agency = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
    if not user_agency:
        logger.error(f'自动提现失败: 合伙人没有绑定微信 agency_uid={agency_uid}')
        session.close()
        return False

    open_id = user_agency.ebf_ua_bind_user_id
    if not open_id:
        logger.error(f'自动提现失败: 合伙人没有绑定微信 agency_uid={agency_uid}')
        session.close()
        return False

    agency_income = (
        session.query(AgencyIncome).filter_by(slbf_ais_agency_uid=agency_uid).first()
    )
    if not agency_income:
        logger.error(f'自动提现失败: 没有实名记录 agency_uid={agency_uid}')
        session.close()
        return False

    name = agency_income.slbf_ais_card_name
    if not name:
        logger.error(f'自动提现失败: 没有实名记录 agency_uid={agency_uid}')
        session.close()
        return False

    if not add_mq_cash_task(open_id, cash_method, agency_uid, amount, name, ip):
        logger.error(f'自动提现失败: 添加提现任务失败 agency_uid={agency_uid}')
        session.close()
        return False
    session.close()
    logger.info(f'自动提现: 添加提现任务成功')
    return True


def create_partner_inventory(order_id, source=None):
    """
    创建个人店主库存记录
    新个人店主支付1980元成功后，给他的【我的存酒】账户存进去三款酒，分别是好酒编号
    665231918615119、627637505511425、637312428917318，每款酒预存6支，总计18支
    """

    class GoodsOrder:
        pass

    class UserInventory(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user_inventory', 'model': UserInventory},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'订单不存在 {order_id}')
        session.close()
        return False

    if pay.sdef_order_type != OrderType.MEMBER:
        logger.info(f'非个人店主注册订单: {order_id}')
        session.close()
        return False

    logger.info(f'create_partner_inventory: order_id={order_id} source={source}')
    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return False

    try:
        oid = pay.sdef_order_device_id
        cart_goods = promotion.PARTNER_GOODS  # 1980元个人云店商品
        goods_id = cart_goods[0]['id']
        count = cart_goods[0]['count']
        filters = dict(user_id=oid, goods_id=goods_id, status=1)
        ui = session.query(UserInventory).filter_by(**filters).first()
        now = datetime.datetime.now()
        redis = redis_util.client
        pingui_id = redis.get(f'pingui_{order_id}')
        if ui or pingui_id:
            msg = f'create_inventory 已加入库存: order_id={order_id}, oid={oid}, source={source}'
            if source:
                logger.info(msg)
            else:
                logger.error(msg)
            session.close()
            return False

        redis.setex(f'pingui_{order_id}', 3600, 10)
        for g in cart_goods:
            ui = UserInventory()
            ui.user_id = oid
            ui.goods_id = g['id']
            ui.inventory = g['count']
            ui.status = 1
            ui.access_record = json.dumps({'add': [{order_id: count}], 'minus': []})
            ui.effect_time = now
            ui.create_time = now
            session.add(ui)
            session.commit()
            logger.info(
                f'create_inventory success: order_id={order_id} goods_id={ui.goods_id} count={ui.inventory} source={source}')
        session.close()
        return True
    except Exception as e:
        logger.error(f'create_inventory fail: order_id={order_id}, error={e}, oid={oid} source={source}')
        session.close()
        return False


def create_user_inventory(order_id, source=None):
    """创建用户库存记录"""

    class GoodsOrder:
        pass

    class UserInventory(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user_inventory', 'model': UserInventory},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'订单不存在 {order_id}')
        session.close()
        return

    if pay.sdef_order_type != OrderType.PINGUI:
        logger.info(f'非拼购订单: {order_id}')
        session.close()
        return

    logger.info(f'create_user_inventory: order_id={order_id} source={source}')
    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单 {order_id}')
        session.close()
        return

    try:
        oid = pay.sdef_order_device_id
        cart_goods = json.loads(pay.sdef_order_goods)
        goods_id = cart_goods[0]['id']
        count = cart_goods[0]['count']
        filters = dict(user_id=oid, goods_id=goods_id, status=1)
        ui = session.query(UserInventory).filter_by(**filters).first()
        now = datetime.datetime.now()
        redis = redis_util.client
        pingui_id = redis.get(f'pingui_{order_id}')
        if ui:
            access_record = ui.access_record
            is_minus = order_id in access_record
            logger.info(f'access_record={access_record}')
            if pingui_id or is_minus:
                msg = f'create_inventory 已加入库存: order_id={order_id}, oid={oid}, source={source}'
                if source:
                    logger.info(msg)
                else:
                    logger.error(msg)
                access_record = json.loads(access_record)
                access_record['add'] = [{order_id: count}]
                ui.access_record = json.dumps(access_record)
                session.commit()
                session.close()
                return

            redis.setex(f'pingui_{order_id}', 3600, 10)
            num = ui.inventory
            log_msg = f'create_inventory success:order_id={order_id} old_inventory={num} count={count} source={source}'
            logger.info(log_msg)
            ui.inventory += count
            access_record = json.loads(access_record)
            access_record['add'].append({order_id: count})
            ui.access_record = json.dumps(access_record)
            ui.update_time = now
        else:
            if pingui_id:
                msg = f'create_inventory 已加入库存: order_id={order_id}, oid={oid}, source={source}'
                if source:
                    logger.info(msg)
                else:
                    logger.error(msg)
                session.close()
                return

            redis.setex(f'pingui_{order_id}', 3600, 10)
            ui = UserInventory()
            ui.user_id = oid
            ui.goods_id = goods_id
            ui.inventory = count
            ui.status = 1
            ui.access_record = json.dumps({'add': [{order_id: count}], 'minus': []})
            ui.effect_time = now
            ui.create_time = now
            session.add(ui)
            log_msg = f'create_inventory success: order_id={order_id} old_inventory=0 count={count} source={source}'
            logger.info(log_msg)
        session.commit()
        session.close()
        return
    except Exception as e:
        logger.error(
            f'create_inventory fail: order_id={order_id}, error={e}, oid={oid} source={source}'
        )
        session.close()
        return


def minus_user_inventory(order_id, source=None):
    """减少用户库存"""

    class GoodsOrder:
        pass

    class UserInventory(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user_inventory', 'model': UserInventory},
        ]
    )

    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'订单不存在: order_id = {order_id}, source = {source}')
        session.close()
        return

    if pay.sdef_order_type != OrderType.PINQU:
        logger.info(f'非取酒订单: order_id = {order_id}, source = {source}')
        session.close()
        return

    logger.info(f'minus_user_inventory: order_id={order_id} source = {source}')
    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.info(f'非已支付订单: order_id={order_id} source = {source} ')
        session.close()
        return

    try:
        redis = redis_util.client
        cart_goods = json.loads(pay.sdef_order_goods)
        goods_packing_id = ['571983673114813', '571983568187916']  # 商品包装ID列表
        goods_info = list(
            filter(lambda g: g['id'] not in goods_packing_id, cart_goods)
        )[0]
        goods_id = goods_info['id']
        count = goods_info['count']
        filters = dict(user_id=pay.sdef_order_device_id, goods_id=goods_id, status=1)
        ui = session.query(UserInventory).filter_by(**filters).first()
        pinqu_id = redis.get(f'pinqu_{order_id}')
        access_record = ui.access_record
        logger.info(f'access_record={access_record}')
        is_minus = order_id in access_record
        access_record = json.loads(access_record)
        access_record['minus'] = [{order_id: count}]
        if not is_minus and not pinqu_id:
            num = ui.inventory
            log_msg = f'minus_inventory success:order_id={order_id} old_inventory={num} count=-{count} source={source}'
            logger.info(log_msg)
            redis.setex(f'pinqu_{order_id}', 3600, 10)
            ui.access_record = json.dumps(access_record)
            ui.update_time = datetime.datetime.now()
            ui.inventory -= count
        else:
            ui.access_record = json.dumps(access_record)
            logger.info(f'minus_inventory 已减库存: order_id={order_id} source={source}')

        session.commit()
        session.close()
        return
    except Exception as e:
        logger.error(
            f'minus_inventory fail: order_id={order_id}, error={e}, source={source}'
        )
        session.close()
        return


def pin_coupon(open_id, goods_id):
    """
    新用户第一个拼柜订单自动抵扣零售第一瓶实付金额

    pin_coupon('o7qyl0i6R30kbFS7KPFVGwYb05pY', '523948811961181')


    :param open_id:
    :return: 优惠金额
    """

    class GoodsOrder(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
        ]
    )

    pin_order = (
        session.query(GoodsOrder)
        .filter_by(
            sdef_order_device_id=open_id,
            sdef_order_pay_status=PayStatus.SUCCESS,
            sdef_order_type=OrderType.PINGUI,
        )
        .first()
    )
    if pin_order:
        logger.info(f'拼柜优惠：0 不是第一次拼柜 open_id={open_id} goods_id={goods_id}')
        session.close()
        return Decimal('0.00')

    orders = (
        session.query(GoodsOrder)
        .filter_by(
            sdef_order_device_id=open_id, sdef_order_pay_status=PayStatus.SUCCESS
        )
        .all()
    )

    for o in orders:
        goods = json.loads(o.sdef_order_goods) if o.sdef_order_goods else None
        if goods:
            for g in goods:
                if g['id'] == goods_id:
                    session.close()
                    return Decimal(g['goods_price'])
    session.close()
    return Decimal('0.00')


def recommender_random_bonus(order_id, source=None):
    """新人大礼包推荐人随机红包奖励：goods_id=promotion.NEW_CUSTOMER_PROMO_GOODS_ID"""

    class GoodsOrder:
        pass

    class Benefit(object):
        pass

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class AccountMoney(object):
        pass

    class Pay(object):
        pass

    class ChargeRecord(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_account_money', 'model': AccountMoney},
            {'db_table': 'ebt_pay', 'model': Pay},
            {'db_table': 'ebt_charge_record', 'model': ChargeRecord},
        ]
    )

    goods_id = promotion.NEW_CUSTOMER_PROMO_GOODS_ID
    pay = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
    if not pay:
        logger.error(f'recommender_random_bonus: 订单不存在 order_id = {order_id}')
        session.close()
        return

    if pay.sdef_order_type == OrderType.MEMBER:
        session.close()
        return

    if goods_id not in pay.sdef_order_goods:
        session.close()
        return

    logger.info(f'recommender_random_bonus: order_id={order_id} source={source}')
    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.error(f'recommender_random_bonus: 订单未支付 order_id={order_id}')
        session.close()
        return

    try:
        money = round(random.uniform(1, 5), 2)  # 随机红包金额
        fee = pay.sdef_order_fee
        rate = round(money / float(fee), 2)
        user_id = pay.sdef_order_device_id
        user = session.query(User).filter_by(ebf_user_id=user_id).first()
        recommend_id = user.ebf_user_recommend_user
        name = user.ebf_user_nickname
        if not recommend_id:
            logger.error(
                f'recommender_random_bonus: order_id={order_id} recommend_id={recommend_id} source={source}'
            )
            session.close()
            return

        recommend_ua = (
            session.query(UserAgency)
            .filter_by(ebf_ua_bind_user_id=recommend_id)
            .first()
        )
        if recommend_ua:
            recommend_agency_id = recommend_ua.ebf_agency_id
            if recommend_agency_id == config.DEFAULT_AGENCY_ID:
                logger.error(
                    f'recommender_random_bonus: order_id={order_id} recommend_agency_id={recommend_agency_id}'
                )
                session.close()
                return
            recommend_agency = (
                session.query(Agency)
                .filter_by(ebf_agency_id=recommend_agency_id)
                .first()
            )
            recommend_uid = recommend_agency.ebf_agency_uid
            filters = dict(agency_uid=recommend_uid, order_id=order_id, type=2)
            bf = session.query(Benefit).filter_by(**filters).first()
            if bf:
                msg = f'recommender_random_bonus:已奖励 order_id={order_id} recommend_id={recommend_id} source={source}'
                logger.info(msg)
                session.close()
                return
            first = f'恭喜您邀请的朋友“{name}”购买新人大礼包成功！特别奖励{money}元收益红包'
            key = '新人大礼包推荐人奖励'
            now = datetime.datetime.now()
            benefit = Benefit()
            benefit.order_id = order_id
            benefit.factory_uid = config.FACTORY_UID
            benefit.agency_uid = recommend_uid
            benefit.type = 2
            benefit.fee = Decimal(money)
            benefit.order_fee = fee
            benefit.rate = rate
            benefit.status = 1
            benefit.is_valid = 1
            benefit.is_finish = 1
            benefit.remarks = '新人大礼包推荐人随机红包奖励'
            benefit.update_time = now
            benefit.create_time = now
            session.add(benefit)
            tasks.send_benefit_reward_notice.delay(
                first, key, recommend_id, money, order_id
            )
            logger.info(
                f'recommender_random_bonus success: money={money}, order_id={order_id}, recommend_id={recommend_id} {source}'
            )
        else:
            cr = session.query(ChargeRecord).filter_by(ebf_cr_trade_no=order_id).first()
            if cr:
                msg = f'recommender_random_bonus:已奖励 order_id={order_id} recommend_id={recommend_id} source={source}'
                logger.info(msg)
                session.close()
                return
            first = f'恭喜您邀请的朋友“{name}”购买新人大礼包成功！奖励{money}元余额红包已到账，余额可提现到微信钱包或购酒使用！'
            money = Decimal(money)
            result = BalanceHandler.add_account_cash(
                recommend_id, money, order_id, pay_content='新人大礼包推荐人奖励'
            )
            if result:
                am = (
                    session.query(AccountMoney)
                    .filter_by(ebf_am_user_id=recommend_id)
                    .first()
                )
                if not am:
                    am_money = money
                else:
                    am_money = (am.ebf_am_money + money).quantize(Decimal('0.00'))
                am_money = str(am_money)
                tasks.send_balance_reward_notice.delay(
                    recommend_id, money, order_id, am_money, first
                )
                logger.info(
                    f'recommender_random_bonus success: money={money}, order_id={order_id} recommend_id={recommend_id} {source}'
                )
            else:
                logger.error(
                    f'recommender_random_bonus fail: money={money}, order_id={order_id} recommend_id={recommend_id} {source}'
                )

        session.commit()
        session.close()
        return
    except Exception as e:
        logger.error(
            f'recommender_random_bonus fail: order_id={order_id} err={e} {source}'
        )
        session.rollback()
        session.close()
        return


def count_goods_sold(order_id):
    """
    统计商品售量

    count_goods_sold(15571261278261811)

    :param order_id:
    :return:
    """

    class GoodsOrder(object):
        pass

    class Goods(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_goods', 'model': Goods},
        ]
    )

    order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()

    goods = json.loads(order.sdef_order_goods)

    for g in goods:
        goods_id = g['id']
        count = g['count']
        _goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
        _goods.sdef_goods_sold += count
        session.commit()

    session.close()


def order_coupon_notice():
    """
    体验订单拼柜优惠券批量通知

    order_coupon_notice()
    OK

    :param coupon_id:
    :return:
    """

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    cu = (
        session.query(CouponUser)
        .filter_by(
            coupon_id=6,
            status=0,
            is_active=1,
        )
        .all()
    )

    total_amount = Decimal('9.90')
    store_id = 1
    order_type = OrderType.TIYAN

    for c in cu:
        user_id = c.user_id
        order_id = c.order_id

        try:
            first = f'您的恒温红酒拼柜购酒券已到账'
            remark = f'您的99元恒温红酒拼柜购酒券已到账，有效期90天，请尽快使用。全程恒温喝好酒，拼柜批发省好多！\n点击详情使用拼柜购酒券'
            tasks.send_order_pay_success_notice.delay(
                user_id, order_id, total_amount, store_id, order_type, first, remark
            )
            logger.info(f'体验: 发送体验拼柜券通知成功 order_id={order_id} user={user_id}')
        except Exception as e:
            logger.exception(e)
            logger.error(f'体验: 发送体验拼柜券通知失败 order_id={order_id} user={user_id}')


def send_order_status_notice():
    """
    给待激活体验订单发送批量通知

    send_order_status_notice()
    OK

    :return:
    """

    class Order(object):
        pass

    class User(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'sdet_order', 'model': Order},
        ]
    )

    quota = config.TI_YAN_QUOTA
    total_amount = Decimal('9.90')
    store_id = 0
    order_type = OrderType.NORMAL

    orders = (
        session.query(Order)
        .filter_by(
            sdef_order_status=OrderStatus.WAIT_VALID,
        )
        .all()
    )
    for o in orders:
        order_id = o.sdef_order_id
        user_id = o.sdef_order_device_id

        user = session.query(User).filter_by(ebf_user_id=user_id).first()
        if user:
            recommend_order_number = user.ebf_user_recommend_order_number
            delta = quota - recommend_order_number

            # 发送通知
            try:
                first = f'您的体验订单待生效'
                remark = f'您的体验订单还差{delta}个推荐订单才能生效, 请继续邀请朋友下单或到订单详情页自己激活。\n点击详情查看订单'
                tasks.send_order_pay_success_notice.delay(
                    user_id, order_id, total_amount, store_id, order_type, first, remark
                )
                logger.info(f'体验: 发送推荐体验订单激活通知 order_id={order_id} user_id={user_id}')
            except Exception as e:
                logger.exception(e)
                logger.error(f'体验: 发送推荐体验订单数通知失败 order_id={order_id} user_id={user_id}')


def add_recommend_number(open_id):
    """
    增加推荐新用户人数

    add_recommend_number('o7qyl0i6R30kbFS7KPFVGwYb05pY')

    :param open_id:
    :return:
    """

    class User(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
        ]
    )
    user = (
        session.query(User)
        .filter_by(ebf_user_id=open_id, ebf_user_factory_id=config.FACTORY_ID)
        .first()
    )
    recommend_open_id = user.ebf_user_recommend_user
    if not recommend_open_id:
        logger.error(f'增加推荐新用户人数: 没有推荐人 open_id={open_id}')
        session.close()
        return

    recommender = (
        session.query(User)
        .filter_by(ebf_user_id=recommend_open_id, ebf_user_factory_id=config.FACTORY_ID)
        .first()
    )
    if not recommender:
        logger.error(f'增加推荐新用户人数: 没有推荐人 open_id={open_id}')
        session.close()
        return

    recommend_number = recommender.ebf_user_recommend_number
    recommend_number += 1
    recommender.ebf_user_recommend_number = recommend_number
    session.commit()
    session.close()
    logger.info(
        f'增加推荐新用户人数：open_id={open_id} recommender={recommend_open_id} 推荐第{recommend_number}人'
    )


def send_new_user_coupon(open_id):
    """
    发送新用户礼券

    send_new_user_coupon('o7qyl0i6R30kbFS7KPFVGwYb05pY')

    :param open_id:
    :return:
    """

    class User(object):
        pass

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    # 发幸运新用户礼包券
    coupon_id = 8
    coupon_name = '108元现金抵扣券'
    coupon_type = '代金券'

    try:
        coupon = (
            session.query(CouponUser)
            .filter_by(user_id=open_id, coupon_id=coupon_id)
            .first()
        )
        if coupon:
            logger.info(f'发送新用户礼券: 已经发券，不重复发 open_id={open_id} coupon_id=8')
            session.close()
            return

        if not CouponHandler.create_coupon(open_id, coupon_id):
            logger.error(f'发送新用户礼券: NG 创建优惠券失败 open_id={open_id} coupon_id={coupon_id}')
            session.close()
            return
        logger.info(f'发送新用户礼券: open_id={open_id} coupon_id={coupon_id}')

        # 通知新用户
        # lucky = 'lucky_user'
        # first = f'108元新人礼券已放入我的卡券（有效期7天），感谢您关注莱支好酒'
        # remark = f'酒庄官方联合莱支平台补贴推广，新人关注即赠98元现金券半价品鉴，邀请新人关注即赚30元奖金，可消费或提现。'
        # promotion = '券后只需108元两支进口美酒包邮'
        # award = '108元现金券'
        # tasks.send_lucky_draw_notice.delay(
        #     open_id, lucky, first, remark, promotion, award
        # )
    except Exception as e:
        logger.exception(e)


def recharge_new_user_and_recommender_balance(open_id):
    """
    给新用户充值30元

    send_new_user_balance('o7qyl0i6R30kbFS7KPFVGwYb05pY')

    :param open_id:
    :return:
    """

    class User(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
        ]
    )

    user = (
        session.query(User)
        .filter_by(ebf_user_id=open_id, ebf_user_factory_id=config.FACTORY_ID)
        .first()
    )

    nickname = user.ebf_user_nickname
    if nickname == '未关注':
        nickname = ''

    # 给新用户充值30元余额
    money = 30
    describe = '新人奖励'
    result = BalanceHandler.add_manual_money(
        open_id, money, operator='新人奖励', ip='', pay_content=describe
    )
    if result:
        logger.info(f'OK: 新人奖励充值成功 new_user={open_id}')
        # 通知推荐人
        msg = f'欢迎关注酒庄厂商直卖平台-莱支好酒，送您的{money}元奖金已充值到【我的奖金】，可消费、可提现'
        remark = f'奖金可直接消费抵扣部分货款（特价商品除外）；点击【领取奖金】每邀请一人成功下单可提现{money}元，上不封顶'
        logger.info(f'充值成功：OK 充值{money}元余额 open_id={open_id}')
        balance_notice(open_id, money, msg, remark)
    else:
        logger.error(f'NG: 新人奖励充值失败 new_user={open_id}')

    # 给推荐人充值30元余额
    recommender_id = user.ebf_user_recommend_user
    if not recommender_id:
        logger.error(f'发送新用户礼券: 没有推荐人 open_id={open_id}')
        session.close()
        return
    recommender = (
        session.query(User)
        .filter_by(ebf_user_id=recommender_id, ebf_user_factory_id=config.FACTORY_ID)
        .first()
    )
    if not recommender:
        logger.error(f'发送新用户礼券: 没有推荐人 open_id={open_id}')
        session.close()
        return

    money = 30
    describe = '推荐新人奖励'
    result = BalanceHandler.add_manual_money(
        recommender_id, money, operator='推荐新人奖励', ip='', pay_content=describe
    )
    if result:
        logger.info(f'OK: 推荐新人奖励充值成功 new_user={open_id}, recommender={recommender_id}')
        # 通知推荐人
        msg = f'恭喜您推荐的“{nickname}”关注成功，特别奖励您的{money}元可消费奖金已充值到“我的奖金”'
        remark = '您购物时可用奖金抵扣部分货款（部分特殊商品不参与货款抵扣和提现活动）'
        logger.info(f'充值成功：OK 充值{money}元余额 recommend_user={recommender_id}, open_id={open_id}')
        balance_notice(recommender_id, money, msg, remark)
    else:
        logger.error(f'NG: 推荐新人奖励充值失败 new_user={open_id}, recommender={recommender_id}')


def reward_recommender_cashable_balance(order_id: str) -> bool:
    """
    新人首单给推荐人发放奖金
    - 30元可消费可提现奖金

    reward_recommender_cashable_balance(16456700965493887)

    :param order_id: 订单号码
    :return:
    """
    money = Decimal(30)

    order = get_order(order_id)
    order_status = order.sdef_order_status
    order_pay_status = order.sdef_order_pay_status

    if order_pay_status != 1:
        return False

    if (order_status == OrderStatus.COMPLETE and
            order.sdef_order_pay_time > datetime.datetime.strptime('2022-11-08', '%Y-%m-%d')):
        logger.error(f"推荐奖金转为可提现奖金: NG 2022-11-08 切换日期后下单的完成订单不重复充值 order_id={order_id}")
        return False  # 过渡期-切换日期后订单完成不重复转可提现

    if not AgencyHelper.is_first_new_customer_gift_order(order_id):
        return False  # 非新人礼首单

    if promotion.NEW_CUSTOMER_PROMO_GOODS_ID not in order.sdef_order_goods:
        return False  # 非新人礼首单

    user_id = order.sdef_order_device_id
    recommender_id = AgencyHelper.get_recommender_id(user_id)

    # 给推荐人直接发可提现奖金
    if BalanceHandler.add_account_cash(recommender_id, money, order_id, pay_content='新人礼首单奖励'):
        # 通知推荐人
        # msg = f'恭喜您推荐的新人已成交新人礼首单，特别奖励您{money}元可提现奖金以资鼓励'
        # remark = f'备注：订单尾号[{str(order_id)[-4:]}]，您可进入【我的奖金】提现到微信钱包。邀请越多人关注提现机会越多！！！'
        # logger.info(
        #     f'推荐奖转可提现: OK {money}元余额转为可提现 order_id={order_id} recommender={recommender_id}, user={user_id}')
        # balance_notice(recommender_id, money, msg, remark)

        new_customer_gift_order_reward_notice(recommender_id, order_id, money)  # 修改模版 20221113
        return True
    return False


def send_all_new_users_coupon():
    """
    给没下过单的关注新用户发新用户礼券

    send_all_new_users_coupon()

    :return:
    """

    class User(object):
        pass

    class Order(object):
        pass

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'sdet_order', 'model': Order},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    users = (
        session.query(User)
        .filter_by(
            ebf_user_type=0,
            ebf_user_factory_id=config.FACTORY_ID,
            ebf_user_is_subscribe=1,
        )
        .all()
    )
    for user in users:
        user_id = user.ebf_user_id
        order = (
            session.query(Order)
            .filter_by(sdef_order_device_id=user_id, sdef_order_pay_status=1)
            .first()
        )
        if not order:
            # 是否已发券？
            coupon = (
                session.query(CouponUser)
                .filter_by(user_id=user_id, coupon_id=8)
                .first()
            )
            if not coupon:
                logger.info(f'发送新用户礼券：open_id={user_id}')
                try:
                    send_new_user_coupon(user_id)
                except Exception as e:
                    logger.exception(e)


def send_lucky_users_coupon(number):
    """
    给幸运用户发幸运礼券

    send_lucky_users_coupon(100)

    :param number: 抽奖人数
    :return:
    """

    class User(object):
        pass

    class Order(object):
        pass

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'sdet_order', 'model': Order},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    users = (
        session.query(User)
        .filter_by(
            ebf_user_type=0,
            ebf_user_factory_id=config.FACTORY_ID,
            ebf_user_is_subscribe=1,
        )
        .all()
    )
    total = len(users)

    i = 0
    j = 0
    while i < number and j < total:
        j += 1
        user = users[int(random.random() * total)]
        open_id = user.ebf_user_id
        # 是否已发券？
        coupon = (
            session.query(CouponUser).filter_by(user_id=open_id, coupon_id=8).first()
        )
        if not coupon:
            try:
                # 发幸运新用户礼包券
                CouponHandler.create_coupon(open_id, 8)
                i += 1
                logger.info(
                    f'发送幸运用户礼券: open_id={open_id} coupon_id=8 No.: {i} / {j} / {total}'
                )
                # 通知新用户
                lucky = 'lucky'
                first = f'恭喜您成为莱支好酒的幸运用户，获赠200元200元无门槛现金券！'
                remark = f'200元无门槛现金券已到账，有效期7天。分享新用户下单，马上送感谢礼券。\n点击详情使用礼券'
                promotion = f'幸运大奖'
                tasks.send_lucky_draw_notice.delay(
                    open_id, lucky, first, remark, promotion
                )
            except Exception as e:
                logger.exception(e)


def send_goods_coupon(order_id):
    """
    给特殊商品返券

    send_goods_coupon('15478701444703303')

    :param order_id:
    :return:
    """

    coupon_goods = ['592451918991040']
    coupon_id = 9
    promotion = '智利名庄首单全返'

    class GoodsOrder:
        pass

    class User(object):
        pass

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    try:
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
        user_id = order.sdef_order_device_id
        goods = json.loads(order.sdef_order_goods)
        for g in goods:
            if g['id'] in coupon_goods:
                if not CouponHandler.create_coupon(user_id, coupon_id, order_id):
                    logger.error(
                        f'商品返券：NG create_coupon open_id={user_id} order_id={order_id} coupon_id={coupon_id}'
                    )
                    session.close()
                    return

                logger.info(
                    f'商品返券: open_id={user_id} order_id={order_id} coupon_id={coupon_id}'
                )
                lucky = 'goods_coupon'
                first = '您的“智利名庄首单全返”198元无门槛现金券已生效，有效期7天，可线上任购全场所有商品（活动商品除外）。请尽快使用以免过期！'
                remark = '点击查看优惠券详情及使用规则！'
                tasks.send_lucky_draw_notice.delay(
                    user_id, lucky, first, remark, promotion
                )

                # 通知推荐人
                user = session.query(User).filter_by(ebf_user_id=user_id).first()
                recommend_id = user.ebf_user_recommend_user
                if recommend_id:
                    recommend_coupon_id = 7
                    coupon = (
                        session.query(CouponUser)
                        .filter_by(
                            user_id=recommend_id,
                            coupon_id=recommend_coupon_id,
                            order_id=order_id,
                        )
                        .first()
                    )
                    if coupon:
                        logger.error(
                            f'给推荐人发券: 已经发券，不重复发 open_id={user_id} order_id={order_id} coupon_id={recommend_coupon_id}'
                        )
                        session.close()
                        return
                    if not CouponHandler.create_coupon(
                            recommend_id, recommend_coupon_id, order_id
                    ):
                        logger.error(
                            f'给推荐人发券: NG open_id={recommend_id} order_id={order_id} coupon_id={recommend_coupon_id}'
                        )
                        session.close()
                        return
                    logger.info(
                        f'给推荐人发券: open_id={recommend_id} order_id={order_id} coupon_id={recommend_coupon_id}'
                    )
                    # 通知推荐人
                    lucky = 'goods_coupon_recommend'
                    first = (
                        f'感谢你的朋友{user.ebf_user_nickname}在莱支好酒下单，特赠你200元无门槛现金抵扣券（活动商品除外）'
                    )
                    remark = (
                        f'200元无门槛现金抵扣券已到账，有效期7天，请尽快使用以免过期！多多分享，多多优惠！\n点击查看优惠券详情及使用规则'
                    )
                    tasks.send_lucky_draw_notice.delay(
                        recommend_id, lucky, first, remark, promotion
                    )
    except Exception as e:
        logger.error(f'商品返券券：NG order_id={order_id}')
        logger.exception(e)


def send_recommend_coupon(order_id):
    """
    给推荐人送新人礼包券

    :param order_id:
    :return:
    """

    class GoodsOrder:
        pass

    class User(object):
        pass

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    try:
        coupon_id = 8
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()

        # 新人礼包订单给推荐人送券
        goods_id = promotion.NEW_CUSTOMER_PROMO_GOODS_ID  # 新人礼包
        goods_info = order.sdef_order_goods
        if goods_id not in goods_info:
            logger.info(f'非新人礼包订单不送券 order_id={order_id}')
            session.close()
            return

        user_id = order.sdef_order_device_id
        user = session.query(User).filter_by(ebf_user_id=user_id).first()
        nickname = user.ebf_user_nickname
        if nickname == '未关注':
            nickname = ''
        recommend_id = user.ebf_user_recommend_user
        # 发券
        if recommend_id:
            coupon = (
                session.query(CouponUser)
                .filter_by(user_id=recommend_id, coupon_id=coupon_id, order_id=order_id)
                .first()
            )
            if coupon:
                logger.info(
                    f'给推荐人发券: 已经发券，不重复发 open_id={user_id} coupon_id={coupon_id} order_id={order_id}'
                )
                session.close()
                return
            if not CouponHandler.create_coupon(recommend_id, coupon_id, order_id):
                logger.error(
                    f'给推荐人发券: NG open_id={recommend_id} order_id={order_id} coupon_id={coupon_id}'
                )
                session.close()
                return
            logger.info(
                f'给推荐人发券: OK open_id={recommend_id} order_id={order_id} coupon_id={coupon_id}'
            )
            # 通知推荐人
            lucky = 'recommend_coupon'
            first = f'感谢你的朋友{nickname}在莱支好酒下单，特赠你150元新人礼包现金抵扣券'
            remark = f'150元新人礼包现金抵扣券已到账，有效期7天，请尽快使用以免过期。多多分享，多多优惠！\n点击详情查看礼券'
            tasks.send_lucky_draw_notice.delay(recommend_id, lucky, first, remark)
    except Exception as e:
        logger.error(f'给推荐人发券：NG order_id={order_id}')
        logger.exception(e)


def send_trial_coupon(order_id):
    """
    样品订单返券

    send_trial_coupon(16001629682342069)

    :param order_id:
    :return:
    """

    class GoodsOrder:
        pass

    class User(object):
        pass

    class CouponUser(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
        ]
    )

    try:
        coupon_id = 10
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()

        if order.sdef_order_type != OrderType.TRIAL:
            logger.info(f'send_trial_coupon: 非样品订单不返券 order_id={order_id}')
            session.close()
            return

        goods_arr = json.loads(order.sdef_order_goods)
        if len(goods_arr) != 1:
            logger.error(f'send_trial_coupon: 样品订单商品项目数量不为1 order_id={order_id}')
            session.close()
            return

        goods = goods_arr[0]
        if goods['count'] != 1:
            logger.error(f'send_trial_coupon: 样品订单商品数量不为1 order_id={order_id}')
            session.close()
            return

        goods_id = goods['id']
        user_id = order.sdef_order_device_id
        money = order.sdef_order_fee

        if money == goods['goods_member_price'] or money == goods['goods_pin_price']:
            logger.error(f'send_trial_coupon: 非零售价样酒订单不返券: order_id={order_id}')
            session.close()
            return

        # 发券
        if user_id:
            coupon = (
                session.query(CouponUser)
                .filter_by(user_id=user_id, coupon_id=coupon_id, order_id=order_id)
                .first()
            )
            if coupon:
                logger.info(
                    f'send_trial_coupon: 已经发券，不重复发 open_id={user_id} coupon_id={coupon_id} order_id={order_id}'
                )
                session.close()
                return

            if not CouponHandler.create_coupon(
                    user_id, coupon_id, order_id, money, goods_id
            ):
                logger.error(
                    f'send_trial_coupon: NG open_id={user_id} order_id={order_id} coupon_id={coupon_id}'
                )
                session.close()
                return
            logger.info(
                f'send_trial_coupon: OK open_id={user_id} order_id={order_id} coupon_id={coupon_id}'
            )
            # 通知用户
            lucky = 'trial_coupon'
            first = f'感谢您在莱支好酒下样品订单，特返{money}元现金抵扣券'
            remark = f'{money}元现金抵扣券已到账，有效期15天，请尽快使用以免过期。\n点击详情查看优惠券'
            promotion = f'首瓶全返'
            award = f'现金抵扣券'
            tasks.send_lucky_draw_notice.delay(
                user_id, lucky, first, remark, promotion, award
            )
    except Exception as e:
        logger.error(f'send_trial_coupon: NG order_id={order_id}')
        logger.exception(e)


# 合伙人注册支付后处理===============================================
def create_benefit(out_trade_no, uid, money, pay_fee, type, rate, remarks='加盟费奖励'):
    """
    创建收益奖励
    :param out_trade_no:
    :param inviter_uid:
    :param money:
    :param pay_fee:
    :param type:
    :return:
    """

    class Benefit(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_benefit', 'model': Benefit},
        ]
    )
    try:
        benefit = Benefit()
        now = datetime.datetime.now()
        benefit.order_id = out_trade_no
        benefit.factory_uid = config.FACTORY_UID
        benefit.agency_uid = uid
        benefit.type = type
        benefit.fee = Decimal(money)
        benefit.order_fee = Decimal(pay_fee)
        benefit.rate = rate
        benefit.status = 1
        benefit.is_valid = 1
        benefit.is_finish = 1
        benefit.remarks = remarks
        benefit.update_time = now
        benefit.create_time = now
        session.add(benefit)
        session.commit()
    except Exception as e:
        logger.error(e)
        session.close()
        return False
    session.close()
    return True


def benefit_handle(
        trade_no, uid, type, money, fee, rate, open_id, first, key, touser, remarks='加盟费奖励'
):
    class Benefit(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_benefit', 'model': Benefit},
        ]
    )
    filters = dict(order_id=trade_no, agency_uid=uid, fee=Decimal(money), type=type)
    b = session.query(Benefit).filter_by(**filters).first()
    if not b:
        result = create_benefit(trade_no, uid, money, fee, type, rate, remarks)
        if result:
            logger.info(
                '奖励成功: open_id=%s, order_id=%s, touser=%s, money=%s, uid=%s'
                % (open_id, trade_no, touser, money, uid)
            )
            tasks.send_benefit_reward_notice.delay(first, key, touser, money, trade_no)
        else:
            logger.info(
                '奖励失败: open_id=%s, order_id=%s, touser=%s, money=%s, uid=%s'
                % (open_id, trade_no, touser, money, uid)
            )
    else:
        logger.error(
            '收益奖励已创建: open_id=%s, order_id=%s, touser=%s, money=%s, uid=%s'
            % (open_id, trade_no, touser, money, uid)
        )


def handle_agency_register_order(fee, open_id, trade_no, count, order_describe, sign):
    """
    合伙人注册订单后处理
    """

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class Benefit(object):
        pass

    class Pay(object):
        pass

    class Order(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_pay', 'model': Pay},
            {'db_table': 'sdet_order', 'model': Order},
        ]
    )

    # 辨别是否首次进入合伙人后台记号
    try:
        db = mongodb_util.db
        result = db.users_login.find_one({'_id': open_id})
        if not result:
            data = {'_id': open_id, 'login_times': 0}
            db.users_login.insert(data)
    except Exception as e:
        logging.error(f'partner_handle: fail error={e}')

    user = session.query(User).filter_by(ebf_user_id=open_id).first()
    name = user.ebf_user_nickname
    inviter_oid = user.ebf_user_recommend_user
    inviter_uid = AgencyHelper.get_agency_uid(inviter_oid)

    user_agency = (
        session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
    )
    agency = (
        session.query(Agency).filter_by(ebf_agency_id=user_agency.ebf_agency_id).first()
    )
    agency_id = agency.ebf_agency_id
    agency_uid = agency.ebf_agency_uid

    # 获取事业合伙人
    career_agency = AgencyHelper.get_career_agency(agency_uid)

    if '联营店主注册' in order_describe:
        agency.ebf_agency_is_active = 1  # 开通账号

        # 给1980元个人店主存酒
        order = session.query(Order).filter_by(sdef_order_id=trade_no).first()
        if order.sdef_order_fee == Decimal(1980):
            if create_partner_inventory(trade_no):
                logger.info(f'OK 给个人店主存酒成功 order_id={trade_no}')
            else:
                logger.error(f'NG 给个人店主存酒失败 order_id={trade_no}')

        """
        20230101 店主注册 （1980元 或 3980元）
        一、店主直推新店主（即A推B）A得500元奖金，A的服务商得200元，A的服务商推荐人得50元；
        二、服务商直推店主，服务商得500+200元，服务商的推荐人得50元；
        一次性奖励为实时到账提现，不用7天后提现
        """
        # 20230101 直推奖
        invite_agency = AgencyHelper.get_agency(inviter_uid)
        invite_agency_type = invite_agency.ebf_agency_type
        invite_agency_sub_type = invite_agency.ebf_agency_sub_type
        if invite_agency_type == AgencyType.STORE and invite_agency_sub_type > 2:
            # 服务商直推店主，服务商得500+200元合并为700元
            first = '恭喜您邀请的 “' + name + '” 成功注册店主账号！'
            key = '邀请联营店主奖励'
            remarks = '加盟费奖励'
            money = 500 + 200
            rate = 1
            benefit_handle(
                trade_no,
                inviter_uid,
                BenefitType.PARENT,
                money,
                fee,
                rate,
                open_id,
                first,
                key,
                inviter_oid,  # Receiver
                remarks,
            )
            logger.info(
                f'加盟费收益: 服务商邀请店主奖励: open_id={open_id}, order_id={trade_no}, inviter_uid={inviter_uid}, money={money}'
            )
        else:
            # 店主推荐店主得500元
            if invite_agency_type == AgencyType.STORE and invite_agency_sub_type < 3:
                first = '恭喜您邀请的 “' + name + '” 成功注册店主账号！'
                key = '邀请联营店主奖励'
                remarks = '加盟费奖励'
                money = 500
                rate = 1
                benefit_handle(
                    trade_no,
                    inviter_uid,
                    BenefitType.PARENT,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    inviter_oid,  # Receiver
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 店主邀请店主奖励: open_id={open_id}, order_id={trade_no}, inviter_uid={inviter_uid}, money={money}'
                )

                # 服务商名下店主直推新店主，服务商得200元
                career_agency_uid = career_agency.ebf_agency_uid
                career_agency_id = career_agency.ebf_agency_id
                career_oid = AgencyHelper.get_agency_openid(career_agency_id)
                first = '恭喜您邀请的 “' + name + '” 成功注册联营店主！'
                key = '邀请联营店主奖励'
                remarks = '加盟费奖励'
                money = 200
                rate = 1
                benefit_handle(
                    trade_no,
                    career_agency_uid,
                    BenefitType.CAREER,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    career_oid,  # Receiver
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 服务商奖励: open_id={open_id}, order_id={trade_no}, inviter_uid={inviter_uid}, money={money}'
                )
            else:
                logger.error(
                    f'加盟费收益: 非店主推荐店主不给一次性奖励:  agency_uid={inviter_uid} agency_type={invite_agency_type} agency_sub_type={invite_agency_sub_type}')
        # 20221002 给服务商的推荐人的奖励50元
        invite_career_agency = AgencyHelper.get_agency(career_agency.ebf_agency_parent_id)
        if invite_career_agency:
            invite_career_agency_uid = invite_career_agency.ebf_agency_uid
            invite_career_agency_id = invite_career_agency.ebf_agency_id
            invite_career_oid = AgencyHelper.get_agency_openid(invite_career_agency_id)
            first = '恭喜您名下的服务商团队邀请的 “' + name + '” 成功注册店主账号！'
            key = '邀请联营店主奖励'
            remarks = '加盟费奖励'
            money = 50
            rate = 1
            benefit_handle(
                trade_no,
                invite_career_agency_uid,
                BenefitType.INVITE_CAREER,
                money,
                fee,
                rate,
                open_id,
                first,
                key,
                invite_career_oid,  # Receiver
                remarks,
            )
            logger.info(
                f'加盟费收益: 服务商的推荐人的奖励: open_id={open_id}, order_id={trade_no}, inviter_uid={inviter_uid}, money={money}'
            )
    # 线上分享加盟费处理
    elif 'online' in order_describe:
        # 线上分享 980元加盟费 100/80/20 - 20200818 => 499元 150/80/20 - 20201020
        # 改向邀请人分润为向所属合伙人分润-20201030
        # 1. 新合伙人注册: 重新绑定到邀请人名下，可以改变关系链（抢人）
        # 2. 老合伙人复购: 邀请人默认为上级合伙人

        first = '恭喜您邀请的 “' + name + '” 成功注册合伙人！'
        key = '邀请合伙人注册奖励'
        remarks = '加盟费奖励'

        parent_agency_id = agency.ebf_agency_parent_id
        parent_agency = AgencyHelper.get_agency(parent_agency_id)
        if parent_agency:
            parent_uid = parent_agency.ebf_agency_uid
            parent_ua = (
                session.query(UserAgency)
                .filter_by(ebf_agency_id=parent_agency_id)
                .first()
            )
            parent_oid = parent_ua.ebf_ua_bind_user_id

            # 1。给上级分润150
            msg = 'inviter_uid={}, oid={}, order_id={}, inviter_oid={}, parent_agency_id={}'
            logger.info(
                msg.format(
                    inviter_uid, open_id, trade_no, inviter_oid, parent_agency_id
                )
            )

            # 排除前面3个非全返980订单
            exclusive_orders = [15947753383712753, 15960005848253398, 15960128396956934]

            # 查该合伙人上级（邀请人）名下支付980元或499元加盟费的合伙人数
            n = 0
            agencies = (
                session.query(Agency)
                .filter_by(ebf_agency_parent_id=parent_agency_id)
                .all()
            )
            for a in agencies:
                # 名下多少合伙人购买合伙人980元/499元
                _open_id = AgencyHelper.get_agency_openid(a.ebf_agency_id)
                orders = (
                    session.query(Order)
                    .filter_by(
                        sdef_order_device_id=_open_id,
                        sdef_order_type=OrderType.MEMBER,
                        sdef_order_pay_status=1,
                    )
                    .filter(Order.sdef_order_describe.contains('online'))
                    .filter(Order.sdef_order_id not in exclusive_orders)
                    .count()
                )
                if orders:
                    n += 1
            quota = math.floor(n / 3)  # 可返还份数(每3人返1份）

            # 查邀请人买了多少份980元
            buy980 = (
                session.query(Order)
                .filter_by(
                    sdef_order_device_id=parent_oid,
                    sdef_order_type=OrderType.MEMBER,
                    sdef_order_pay_status=1,
                    sdef_order_describe='online1',
                    sdef_order_fee=Decimal(980),
                )
                .filter(Order.sdef_order_id not in exclusive_orders)
                .count()
            )
            # 查邀请人买了多少份499元
            buy499 = (
                session.query(Order)
                .filter_by(
                    sdef_order_device_id=parent_oid,
                    sdef_order_type=OrderType.MEMBER,
                    sdef_order_pay_status=1,
                    sdef_order_fee=Decimal(499),
                )
                .filter(Order.sdef_order_id not in exclusive_orders)
                .count()
            )
            buy = buy980 + buy499

            # 查已经返了780元多少份
            got780 = (
                session.query(Benefit)
                .filter_by(
                    agency_uid=parent_uid,
                    remarks=remarks,
                    fee=Decimal('780.00'),
                )
                .count()
            )
            # 查已经返了680元多少份
            got680 = (
                session.query(Benefit)
                .filter_by(
                    agency_uid=parent_uid,
                    remarks=remarks,
                    fee=Decimal('680.00'),
                )
                .count()
            )
            # 查已经返了199元多少份
            got199 = (
                session.query(Benefit)
                .filter_by(
                    agency_uid=parent_uid,
                    remarks=remarks,
                    fee=Decimal('199.00'),
                )
                .count()
            )
            got = got780 + got680 + got199
            logger.info(
                f'加盟费收益: order_id={trade_no}, parent_agency_id={parent_agency_id} number={n}, quota={quota}, buy={buy}, got780={got780}, got680={got680}, got199={got199}'
            )

            if quota >= buy980 > (got780 + got680):
                # 给邀请人分润: 可返份数超过或等于购买980份数而且还没全部返还，则返还780元 - 20200821 => 改为返还680元 2020-10-20
                money = 680
                rate = 1
                benefit_handle(
                    trade_no,
                    parent_uid,
                    BenefitType.PARENT,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    parent_oid,
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 第{n}个合伙人注册: open_id={open_id}, order_id={trade_no}, parent_agency_id={parent_agency_id}, money={money}'
                )

            elif quota >= buy > got:
                # 给邀请人分润: 可返份数超过或等于购买份数而且还没全部返还，则返还199元 - 2020-10-20
                money = 199
                rate = 1
                benefit_handle(
                    trade_no,
                    parent_uid,
                    BenefitType.PARENT,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    parent_oid,
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 第{n}个合伙人注册: open_id={open_id}, order_id={trade_no}, parent_agency_id={parent_agency_id}, money={money}'
                )
            else:
                # 否则给邀请人分润: 100元 2020-08-21 -> 150元 2020-10-20
                money = 150
                rate = 1
                benefit_handle(
                    trade_no,
                    parent_uid,
                    BenefitType.PARENT,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    parent_oid,
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 第{n}个合伙人注册: open_id={open_id}, order_id={trade_no}, parent_agency_id={parent_agency_id}, money={money}'
                )

            # 2。给所属门店分润80
            store_agency = AgencyHelper.get_store_agency(agency_uid)
            if store_agency:
                store_agency_uid = store_agency.ebf_agency_uid
                store_agency_id = store_agency.ebf_agency_id
                store_ua = (
                    session.query(UserAgency)
                    .filter_by(ebf_agency_id=store_agency_id)
                    .first()
                )
                touser = store_ua.ebf_ua_bind_user_id if store_ua else None
                first = '恭喜您团队名下成员邀请的 “' + name + '” 成功注册合伙人！'
                money = 80
                rate = 1
                benefit_handle(
                    trade_no,
                    store_agency_uid,
                    BenefitType.CAREER,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    touser,
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 门店收益 open_id={open_id}, order_id={trade_no}, store_agency_id={store_agency_id}, money={money}'
                )

                # 3。给门店所属城市运营中心分润20
                city_agency = AgencyHelper.get_career_agency(store_agency_uid)
                if city_agency:
                    city_agency_id = city_agency.ebf_agency_id
                    city_agency_uid = city_agency.ebf_agency_uid
                    city_ua = (
                        session.query(UserAgency)
                        .filter_by(ebf_agency_id=city_agency_id)
                        .first()
                    )
                    touser = city_ua.ebf_ua_bind_user_id if city_ua else None
                    first = '恭喜您团队名下成员邀请的 “' + name + '” 成功注册合伙人！'
                    money = 20
                    rate = 1
                    benefit_handle(
                        trade_no,
                        city_agency_uid,
                        BenefitType.INVITE_CAREER,
                        money,
                        fee,
                        rate,
                        open_id,
                        first,
                        key,
                        touser,
                        remarks,
                    )
                    logger.info(
                        f'加盟费收益: 城市运营中心收益 open_id={open_id}, order_id={trade_no}, city_agency_id={city_agency_id}, money={money}'
                    )
                else:
                    logger.error(
                        f'加盟费收益: 没有城市运营中心 open_id={open_id}, order_id={trade_no}'
                    )
            else:
                logger.error(f'加盟费收益: 没有事业部 open_id={open_id}, order_id={trade_no}')

            # 4。给运营中心所属公司市场部分润10
            super_agency = AgencyHelper.get_super_agency(city_agency_uid)
            if super_agency:
                super_agency_uid = super_agency.ebf_agency_uid
                super_agency_id = super_agency.ebf_agency_id
                super_ua = (
                    session.query(UserAgency)
                    .filter_by(ebf_agency_id=super_agency_id)
                    .first()
                )
                touser = super_ua.ebf_ua_bind_user_id if super_ua else None
                first = '恭喜您名下团队成员邀请的 “' + name + '” 成功注册合伙人！'
                money = 10
                rate = 1
                benefit_handle(
                    trade_no,
                    super_agency_uid,
                    BenefitType.SUPER_CAREER,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    touser,
                    remarks,
                )
                logger.info(
                    f'加盟费收益: 超级事业部收益 open_id={open_id}, order_id={trade_no}, super_agency_id={super_agency_id}, money={money}'
                )
            else:
                logger.error(f'加盟费收益: 无超级事业部 open_id={open_id}, order_id={trade_no}')
        else:
            logger.error(f'加盟费收益: 无上级合伙人 open_id={open_id}, order_id={trade_no}')
    else:
        # 无效类型
        logger.error(
            '不支持的类型: oid=%s, order_id=%s, describe=%s'
            % (open_id, trade_no, order_describe)
        )
        session.close()
        return

    # 发送支付成功通知
    tasks.send_pay_success_notice.delay(open_id, trade_no, count, fee, order_describe)
    session.commit()
    session.close()


def create_order(count, open_id, trade_no, ip, uid, order_describe):
    """
    创建加盟费订单
    """

    class GoodsOrder(object):
        pass

    class Goods(object):
        pass

    class UserAddress(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_address', 'model': UserAddress},
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'sdet_goods', 'model': Goods},
        ]
    )
    # 幂等处理
    o = session.query(GoodsOrder).filter_by(sdef_order_describe=trade_no).first()
    if o:
        logger.error(f'create_order: 加盟费订单已创建: open_id={open_id}, order_id={trade_no}')
        session.close()
        return

    filters = dict(sdef_address_device_id=open_id, sdef_address_is_del=0)
    address = (
        session.query(UserAddress)
        .filter_by(**filters)
        .order_by(UserAddress.sdef_address_create_time.desc())
        .first()
    )
    if order_describe == 'online':
        goods_list = ['523949213918735']
        remarks = '线上分享赠礼订单'
    elif order_describe == 'online1':
        goods_list = ['594098308634520']
        remarks = '合伙人注册499元赠品订单'
    elif order_describe == 'online2':
        goods_list = ['605581366430028']
        remarks = '合伙人注册499元赠品订单'
    elif order_describe == 'online3':
        goods_list = ['606985016190804']
        remarks = '合伙人注册499元赠品订单'
    elif order_describe == 'crowdfunding':
        goods_list = ['504496545575398']
        remarks = '托管经营赠礼订单'
    elif order_describe in ['underline', 'delegate', 'partnershop']:
        if order_describe == 'delegate':
            goods_list = ['498716605779517', '523949213918735']
            remarks = '委托经营酒柜及LI组合装'
        else:
            goods_list = ['498716605779517']
            if order_describe == 'partnershop':
                remarks = '联合经营酒柜'
            else:
                remarks = '线下开店酒柜'
    elif order_describe == 'adfunding':
        remarks = '梦想众筹订单'
        goods_list = ['523948088470142']
    else:
        logger.error(
            f'create_order: 不支持的类型: open_id={open_id}, order_id={trade_no}, describe={order_describe}'
        )
        session.close()
        return

    cart_goods = []
    if 'online' in order_describe:
        num = 1
    elif order_describe == 'adfunding':
        num = count * 2
    else:
        num = count

    for goods_id in goods_list:
        goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
        # if order_describe == 'adfunding' and goods_id == '498716605779517':
        #     num = 1
        goods_dict = dict(
            id=goods_id,
            count=num,
            goods_img=json.loads(goods.sdef_goods_thumbnail)[0],
            goods_name=goods.sdef_goods_name,
            goods_price=float(goods.sdef_goods_price),
            goods_member_price=float(goods.sdef_goods_member_price),
            goods_pin_price=float(goods.sdef_goods_pin_price),
            balance_rate=0,
            rate=0,
            master_rate=0,
            invite_rate=0,
            invite_invite_rate=0,
            career_rate=0,
            invite_career_rate=0,
            supplier=0,
            goods_cost=float(goods.sdef_goods_cost),
        )
        if goods.sdef_goods_count < num:
            err = '库存不足'
            logging.error(
                f'create_order: fail: err={err}, open_id={open_id}, order_id={trade_no}'
            )
        goods.sdef_goods_count -= num
        cart_goods.append(goods_dict)

    now = datetime.datetime.now()
    try:
        goods_order_id = generator_trade_no()
        order = GoodsOrder()
        order.sdef_order_id = goods_order_id
        order.sdef_order_factory_uid = config.FACTORY_UID
        order.sdef_order_device_id = open_id
        order.sdef_order_fee = 0
        order.sdef_order_goods = json.dumps(cart_goods, cls=JSONEncoder)
        order.sdef_order_balance_fee = 0
        order.sdef_order_name = '加盟费订单'
        order.sdef_order_describe = trade_no
        order.sdef_order_status = 2
        order.sdef_order_pay_status = 1
        order.sdef_order_pay_time = now
        order.sdef_order_type = 1
        order.sdef_order_address_id = address.sdef_address_id if address else None
        order.sdef_order_ip = ip
        order.sdef_order_create_time = now
        order.sdef_order_delivery_fee = 0
        order.sdef_order_agency_uid = uid
        order.sdef_order_remarks = remarks
        session.add(order)
        session.commit()
        logger.info(f'create order: success: open_id={open_id}, order_id={trade_no}')
        # 发订单通知
        send_new_order_notice(goods_order_id)
    except Exception as e:
        session.rollback()
        logger.error(e)
        logger.error(f'create order: fail: open_id={open_id}, order_id={trade_no}')
    finally:
        session.close()


def handle_partner_register_order(order_id):
    """
    handle_partner_register_order('15979805857173681')

    :param order_id:
    :return:
    """

    class GoodsOrder(object):
        pass

    class User(object):
        pass

    class Pay(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class Benefit(object):
        pass

    class CouponUser(object):
        pass

    class CouponOrder(object):
        pass

    class UserInventory(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_pay', 'model': Pay},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_coupon_user', 'model': CouponUser},
            {'db_table': 'ebt_coupon_order', 'model': CouponOrder},
            {'db_table': 'ebt_user_inventory', 'model': UserInventory},
        ]
    )
    _order_array = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).all()
    if len(_order_array) == 0:
        logger.error(f'加盟费处理: 订单不存在！order_id={order_id}')
        session.close()
        return
    if len(_order_array) > 1:
        logger.error(f'加盟费处理: 订单多条记录异常！order_id={order_id}')
        session.close()
        return

    pay = _order_array[0]

    if pay.sdef_order_pay_status != PayStatus.SUCCESS:
        logger.error(f'加盟费处理: 订单未支付！order_id={order_id}')
        session.close()
        return

    pay_fee = pay.sdef_order_fee
    ip = pay.sdef_order_ip
    open_id = pay.sdef_order_device_id

    # 加盟费支付后处理
    if pay.sdef_order_type == OrderType.MEMBER:
        # 普通加盟费支付后处理
        order_describe = pay.sdef_order_describe
        logger.info(
            f'加盟费订单: order_describe: {order_describe}, order_id={order_id}, open_id={open_id}'
        )
        sign = False
        count = None

        user_agency = (
            session.query(UserAgency)
            .filter_by(ebf_ua_bind_user_id=open_id)
            .first()
        )
        agency = (
            session.query(Agency)
            .filter_by(ebf_agency_id=user_agency.ebf_agency_id)
            .first()
        )
        if order_describe == '新事业合伙人注册':
            agency.ebf_agency_type = 3
            agency.ebf_agency_sub_type = 3
        elif order_describe == '联营店主注册':
            # 3.1联营店主注册 20210511
            agency.ebf_agency_type = 3
            agency.ebf_agency_sub_type = 1
            try:
                handle_agency_register_order(
                    pay_fee, open_id, order_id, count, order_describe, sign
                )
            except Exception as e:
                logger.exception(e)
        session.commit()
        session.close()


def migrate_user(open_id):
    """
    从思达尔迁移到金玖宜

    migrate_user('okx0x6BoYaijX8tOx049-TXMf_Fk')

    :param open_id:
    :return:
    """

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class UserInfo(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_agency', 'model': Agency},
        ]
    )

    user = session.query(User).filter_by(ebf_user_id=open_id).first()
    if not user:
        logger.error(f'迁移用户: 用户不存在！open_id={open_id}')
        session.close()
        return

    ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
    if ua:
        # logger.info(f'迁移合伙人: 已经是新合伙人，不迁移 open_id={open_id}')
        session.close()
        return

    account_id = user.ebf_user_account
    old_user = (
        session.query(User)
        .filter_by(ebf_user_account=account_id)
        .filter(User.ebf_user_id.startswith('o7'))
        .first()
    )
    if old_user:
        old_open_id = old_user.ebf_user_id
        old_agency_uid = old_user.ebf_user_agency_uid
        # 如果是老合伙人，更新合伙人登录微信
        old_ua = (
            session.query(UserAgency).filter_by(ebf_ua_bind_user_id=old_open_id).first()
        )
        if old_ua:
            if old_ua.ebf_ua_bind_user_id != open_id:
                old_ua.ebf_ua_bind_user_id = open_id
                agency_id = old_ua.ebf_agency_id
                session.commit()
                logger.info(
                    f'迁移合伙人: {old_open_id} => {open_id}, old_agency_uid={old_agency_uid}, agency_id={agency_id}'
                )
        else:
            # 如果是老用户，更新用户所属合伙人
            agency_uid = user.ebf_user_agency_uid
            if (
                    agency_uid == old_agency_uid
                    or old_agency_uid == config.DEFAULT_AGENCY_UID
            ):
                session.close()
                return
            user.ebf_user_agency_uid = old_agency_uid
            user.ebf_user_agency_is_locked = 1  # 锁定关系
            session.commit()
            logger.info(
                f'迁移用户: {old_open_id} => {open_id}, old_agency_uid={old_agency_uid}'
            )
    session.close()


def lock_user_agency_relation(order_id):
    """
    锁定用户所属合伙人

    lock_user_agency_relation(16002145006537993)

    :param order_id:
    :return:

    """

    if not config.LOCK_USER_AGENCY_ON_ORDER_PAID:
        return

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'ebt_agency', 'model': Agency},
        ]
    )

    order = get_order(order_id)
    user_id = order.sdef_order_device_id
    user = session.query(User).filter_by(ebf_user_id=user_id).first()
    if not user:
        logger.error(f'用户锁定: 用户不存在  user_id={user_id}')
        session.close()
        return
    if user.ebf_user_agency_is_locked:
        session.close()
        return

    # 判断用户是不是合伙人, 合伙人不必处理
    ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=user_id).first()
    if ua:
        session.close()
        return

    # 判断推荐人是否是合伙人，不是合伙人不必处理
    recommender_id = user.ebf_user_recommend_user
    recommender_ua = (
        session.query(UserAgency).filter_by(ebf_ua_bind_user_id=recommender_id).first()
    )
    if not recommender_ua:
        session.close()
        return

    agency_id = recommender_ua.ebf_agency_id
    agency = AgencyHelper.get_agency(agency_id)
    agency_uid = agency.ebf_agency_uid
    old_agency_uid = user.ebf_user_agency_uid
    logger.info(f'用户锁定: 原合伙人UID={old_agency_uid} -> 现合伙人UID={agency_uid}')
    user.ebf_user_agency_uid = agency_uid
    user.ebf_user_agency_is_locked = 1
    session.commit()
    session.close()


def shop_opening_promotion_reward(order_id):
    """
    新店酬宾活动订单后处理

    shop_opening_promotion_reward(16155337547907419)
    """

    # 查客户的推荐人购买份数，可返还次数=购买份数x2，如果实际返还数<可返还数，则返还可提现余额100元，发送通知
    # 如果客户直属运营中心，给运营中心分20元
    # 如果客户直属门店，给门店分20元，给运营中心分10元
    # 如果客户直属合伙人，给合伙人分20元，给门店分10元，给运营中心分10元

    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    class Benefit(object):
        pass

    class Pay(object):
        pass

    class Order(object):
        pass

    session = get_db_session(
        [
            {'db_table': 'ebt_user', 'model': User},
            {'db_table': 'ebt_agency', 'model': Agency},
            {'db_table': 'ebt_user_agency', 'model': UserAgency},
            {'db_table': 'sdet_benefit', 'model': Benefit},
            {'db_table': 'ebt_pay', 'model': Pay},
            {'db_table': 'sdet_order', 'model': Order},
        ]
    )

    order = session.query(Order).filter_by(sdef_order_id=order_id).first()
    if not order:
        logger.error(f'开店酬宾: 订单不存在 order_id={order_id}')
        session.close()
        return

    if promotion.SHOP_OPENING_PROMO_GOODS_ID not in order.sdef_order_goods:
        session.close()
        return

    fee = order.sdef_order_fee
    open_id = order.sdef_order_device_id

    # 客户
    user = session.query(User).filter_by(ebf_user_id=open_id).first()
    name = user.ebf_user_nickname

    # 通知用户
    msg = """
    恭喜您此单被抽中获得2个100元现金红包：点击链接分享活动海报，邀成一人奖100，两人奖200元秒到账秒提现，实际到手价99元/箱。
    https://wx.style999.com/wx/shop_open_promo
    """
    send_text_message(open_id, msg)
    logger.info(f'开店酬宾：给客户推送文本消息 open_id={open_id} order_id={order_id}')

    # 客户的推荐人
    inviter_oid = user.ebf_user_recommend_user
    first = '多谢您邀请的 “' + name + '” 参与新店酬宾活动！'
    key = '新店酬宾奖励'
    remarks = '新店酬宾奖励'

    # 1. 给推荐人返还100
    msg = 'open_id={}, order_id={}, inviter_oid={}'
    logger.info(msg.format(open_id, order_id, inviter_oid))

    # 查邀请人买了多少份
    buy = (
        session.query(Order)
        .filter_by(
            sdef_order_device_id=inviter_oid,
            sdef_order_pay_status=1,
        )
        .filter(Order.sdef_order_goods.contains(promotion.SHOP_OPENING_PROMO_GOODS_ID))
        .count()
    )

    quota = buy * 2

    # 查已经返了100元多少份
    got = (
        session.query(Pay)
        .filter_by(
            ebf_user_id=inviter_oid,
            ebf_pay_account=key,
            ebf_pay_fee=Decimal('100.00'),
            ebf_pay_is_success=1,
            ebf_pay_status=1,
            ebf_pay_type=5,
            ebf_pay_trade_type=2,
        )
        .count()
    )

    logger.info(
        f'新店酬宾: order_id={order_id}, inviter_oid={inviter_oid}, quota={quota}, buy={buy}, got={got}'
    )

    if quota > got:
        # 给邀请人奖励: 应返份数超过已返还份数则返还100元
        touser = inviter_oid
        money = 100
        rate = 1
        if BalanceHandler.add_account_cash(
                inviter_oid, money, order_id, operator='新店酬宾', pay_content=remarks
        ):
            logger.info(
                f'新店酬宾: 奖励充值 OK open_id={open_id}, order_id={order_id}, inviter_oid={inviter_oid}, money={money}'
            )
            tasks.send_benefit_reward_notice.delay(first, key, touser, money, order_id)
        else:
            logger.error(
                f'新店酬宾: 奖励充值 NG open_id={open_id}, order_id={order_id}, inviter_oid={inviter_oid}, money={money}'
            )

    # 2. 直属合伙人直接分20元
    agency = AgencyHelper.get_user_bind_agency(open_id)
    if agency:
        # 用户就是合伙人, 奖励给上级
        agency = AgencyHelper.get_agency(agency.ebf_agency_parent_id)
    else:
        agency = AgencyHelper.get_user_agency(open_id)
    agency_id = agency.ebf_agency_id
    agency_uid = agency.ebf_agency_uid
    agency_type = agency.ebf_agency_type
    agency_sub_type = agency.ebf_agency_sub_type
    ua = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
    touser = ua.ebf_ua_bind_user_id if ua else None
    first = f'恭喜您的团队邀请的朋友{name}参与开店酬宾活动！'
    money = 20
    benefit_handle(
        order_id,
        agency_uid,
        BenefitType.PARENT,
        money,
        fee,
        rate,
        open_id,
        first,
        key,
        touser,
        remarks,
    )
    # 如果直属合伙人就是运营中心, 不再分润
    if not (
            agency_type == AgencyType.CAREER
            or (agency_type == AgencyType.STORE and agency_sub_type == 3)
    ):
        # 3. 如果直属合伙人不是运营中心，给运营中心分10元
        city_agency = AgencyHelper.get_career_agency(agency_uid)
        if city_agency:
            city_agency_id = city_agency.ebf_agency_id
            city_agency_uid = city_agency.ebf_agency_uid
            city_ua = (
                session.query(UserAgency)
                .filter_by(ebf_agency_id=city_agency_id)
                .first()
            )
            touser = city_ua.ebf_ua_bind_user_id if city_ua else None
            first = f'恭喜您的团队邀请的朋友{name}参与开店酬宾活动！'
            money = 10
            rate = 1
            benefit_handle(
                order_id,
                city_agency_uid,
                BenefitType.CAREER,
                money,
                fee,
                rate,
                open_id,
                first,
                key,
                touser,
                remarks,
            )
            logger.info(
                f'新店酬宾: 城市运营中心收益 open_id={open_id}, order_id={order_id}, city_agency_id={city_agency_id}, money={money}'
            )
        else:
            logger.error(f'新店酬宾: 没有城市运营中心 open_id={open_id}, order_id={order_id}')
        if agency_type < 2:
            # 4. 如果直属合伙人是合伙人，给门店分10元
            store_agency = AgencyHelper.get_store_agency(agency_uid)
            if store_agency:
                store_agency_uid = store_agency.ebf_agency_uid
                store_agency_id = store_agency.ebf_agency_id
                store_ua = (
                    session.query(UserAgency)
                    .filter_by(ebf_agency_id=store_agency_id)
                    .first()
                )
                touser = store_ua.ebf_ua_bind_user_id if store_ua else None
                first = f'恭喜您的团队邀请的朋友{name}参与开店酬宾活动！'
                money = 10
                rate = 1
                benefit_handle(
                    order_id,
                    store_agency_uid,
                    BenefitType.STORE,
                    money,
                    fee,
                    rate,
                    open_id,
                    first,
                    key,
                    touser,
                    remarks,
                )
                logger.info(
                    f'新店酬宾: 门店收益 open_id={open_id}, order_id={open_id}, store_agency_id={store_agency_id}, money={money}'
                )
            else:
                logger.error(f'新店酬宾: 没有门店 open_id={open_id}, order_id={open_id}')
    session.commit()
    session.close()


def first_bottle_refund_promotion(order_id):
    """
    限时首瓶全返余额活动
    """
    order = get_order(order_id)
    open_id = order.sdef_order_device_id
    start = datetime.datetime.strptime(promotion.FIRST_REFUND_PROMOTION_START, '%Y-%m-%d')
    end = datetime.datetime.strptime(promotion.FIRST_REFUND_PROMOTION_END, '%Y-%m-%d')
    if not (start < order.sdef_order_pay_time < end):
        # 不在推广时间范围内
        return

    goods_arr = json.loads(order.sdef_order_goods)
    for goods in goods_arr:
        goods_id = goods['id']
        if goods_id in promotion.FIRST_REFUND_PROMOTION_GOODS_ARRAY:
            # 检查是否已经返还
            class Pay(object):
                pass

            session = get_db_session(
                [
                    {'db_table': 'ebt_pay', 'model': Pay},
                ]
            )
            money = goods["goods_price"]
            content = f'首瓶全返goods={goods_id}'
            pay = session.query(Pay).filter_by(
                ebf_user_id=open_id,
                ebf_pay_content=content
            ).all()

            if len(pay) > 0:
                logger.error(f'NG: 首瓶全返充值失败-已有充值记录 user={open_id}, order={order_id}, goods={goods_id}')
                session.close()
                return

            result = BalanceHandler.add_manual_money(
                open_id, money, operator=order_id, ip='', pay_content=content
            )
            if result:
                logger.info(f'OK: 首瓶全返充值成功 user={open_id}, order={order_id}, money={money}, goods={goods_id}')
                # 通知推荐人
                msg = f'感谢您参与限时首瓶返还活动，送您的{money}元奖金已充值到【我的奖金】'
                remark = f'奖金在您购物付款时自动抵扣部分货款（部分特殊商品不参与货款抵扣活动）'
                balance_notice(open_id, money, msg, remark)
                session.close()
            else:
                logger.error(f'NG: 首瓶全返充值失败 user={open_id}, order={order_id}, money={money}, goods={goods_id}')
                session.close()


def new_customer_gift_order_promotion(order_id):
    """
    新人礼下单返90元奖金（订单支付成功送余额）
    """

    class GoodsOrder:
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
        ]
    )

    try:
        order = session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
        goods_id = promotion.NEW_CUSTOMER_PROMO_GOODS_ID  # 新人礼包
        goods_info = order.sdef_order_goods
        if goods_id not in goods_info:
            logger.info(f'非新人礼订单 order_id={order_id}')
            session.close()
            return

        # 新人礼下单返90元奖金
        user_id = order.sdef_order_device_id
        money = 90
        describe = f'新人礼订单返{money}元奖金'
        result = BalanceHandler.add_manual_money(
            user_id, money, operator=f'新人礼订单奖order_id={order_id}', ip='', pay_content=describe
        )
        if result:
            logger.info(f'OK: 新人礼订单奖励充值成功 money={money} user_id={user_id} order_id={order_id}')
            # 通知客户
            msg = f'感谢您参与莱支好酒新人礼活动，您的订单{order_id}，奖励您{money}元购酒余额已到账，之后下单付款时可自动最高抵扣20%货款！'
            remark = f'点击【邀请好友】分享海报邀约新人，每邀1人关注送您30元购酒余额，新人购买新人礼成功后再送您30元现金可秒提现。'
            balance_notice(user_id, money, msg, remark)
        else:
            logger.error(f'NG: 新人礼订单奖励充值失败 money={money} user_id={user_id} order_id={order_id}')
        session.close()
    except Exception as e:
        logger.error(f'NG: 新人礼订单奖励充值失败 money={money} user_id={user_id} order_id={order_id}')
        logger.exception(e)
        session.close()


def recalculate_benefit(start, end):
    """
    重新计算指定时间内的订单收益

    recalculate_benefit('2022-05-23', '2022-06-17')

    """

    class GoodsOrder:
        pass

    session = get_db_session(
        [
            {'db_table': 'sdet_order', 'model': GoodsOrder},
        ]
    )

    start_split = start.split('-')
    start_int_arr = [int(i) for i in start_split]
    start_date = datetime.date(*start_int_arr)

    end_split = end.split('-')
    end_int_arr = [int(i) for i in end_split]
    end_date = datetime.date(*end_int_arr)

    try:
        orders = session.query(GoodsOrder).filter_by(sdef_order_pay_status=1).filter(
            and_(
                GoodsOrder.sdef_order_pay_time > start_date,
                GoodsOrder.sdef_order_pay_time < end_date,
            )).all()
        session.close()
    except Exception as e:
        logger.error(f"NG: recalculate_benefit")
        logger.exception(e)
        session.close()

    for o in orders:
        order_id = o.sdef_order_id
        logger.info(f"START: recalculate_benefit order={order_id} pay_time={o.sdef_order_pay_time}")
        try:
            calculate_pre_benefit(order_id)  # 计算收益
        except Exception as e:
            logger.error(f"NG: recalculate_benefit")
            logger.exception(e)
        try:
            calculate_benefit(order_id)  # 完成订单
        except Exception as e:
            logger.error(f"NG: recalculate_benefit")
            logger.exception(e)
